Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2146 lines
70 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: MINDEX.CXX
  7. //
  8. // Contents: Master Index
  9. //
  10. // Classes: CMasterMergeIndex, CSplitKeyInfo, CTrackSplitKey
  11. //
  12. // History: 30-Mar-94 DwightKr Created stub.
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <pdir.hxx>
  18. #include <fretable.hxx>
  19. #include <rwex.hxx>
  20. #include <pidxtbl.hxx>
  21. #include <cifailte.hxx>
  22. #include <eventlog.hxx>
  23. #include "mindex.hxx"
  24. #include "mcursor.hxx"
  25. #include "fresh.hxx"
  26. #include "fretest.hxx"
  27. #include "indsnap.hxx"
  28. #include "keylist.hxx"
  29. #include "partn.hxx"
  30. unsigned const EIGHT_MEGABYTES = 0x800000;
  31. //+---------------------------------------------------------------------------
  32. //
  33. // Member: CMasterMergeIndex::CMasterMergeIndex, public
  34. //
  35. // Synopsis: Restore an index from storage
  36. //
  37. // Arguments: [storage] -- physical storage
  38. // [widNewMaster] -- workid of new master index
  39. // [iid] -- indexid of new master index
  40. // [widMax] -- largest wid within this index
  41. // [pCurrentMasterIndex] -- current master index, if any
  42. // [widMasterLog] -- workid of master log
  43. // [pMMergeLog] -- optional mmerge log
  44. //
  45. // History: 30-Mar-94 DwightKr Created.
  46. //
  47. //----------------------------------------------------------------------------
  48. CMasterMergeIndex::CMasterMergeIndex( PStorage& storage,
  49. WORKID widNewMaster,
  50. INDEXID iid,
  51. WORKID widMax,
  52. CPersIndex * pCurrentMasterIndex,
  53. WORKID widMasterLog,
  54. CMMergeLog * pMMergeLog ) :
  55. CDiskIndex( iid, CDiskIndex::eMaster, widMax ),
  56. _sigMindex(eSigMindex),
  57. _pCurrentMasterIndex(pCurrentMasterIndex),
  58. _pTargetMasterIndex(0),
  59. _pTargetSink(0),
  60. _widMasterLog(widMasterLog),
  61. _pCompr(0),
  62. _pTrackIdxSplitKey(0),
  63. _ulInitSize(0),
  64. _ulFirstPageInUse(0),
  65. #ifdef KEYLIST_ENABLED
  66. _pTrackKeyLstSplitKey(0),
  67. #endif // KEYLIST_ENABLED
  68. _pNewKeyList(0),
  69. _fAbortMerge(FALSE),
  70. _storage(storage),
  71. _pRWStore(0),
  72. _pIndSnap(0),
  73. _fStateLoaded(FALSE)
  74. {
  75. TRY
  76. {
  77. //
  78. // The on-disk object MUST be fully constructed by the time we
  79. // come here.
  80. //
  81. _pTargetMasterIndex = new CPersIndex( storage,
  82. widNewMaster,
  83. iid,
  84. widMax,
  85. CDiskIndex::eMaster,
  86. PStorage::eOpenForWrite,
  87. TRUE ); // read in the directory
  88. _ulInitSize = _pTargetMasterIndex->GetIndex().PageSize();
  89. _pTargetMasterIndex->GetIndex().SetPageGrowth( EIGHT_MEGABYTES / CI_PAGE_SIZE );
  90. if (0 != _pCurrentMasterIndex)
  91. _pCurrentMasterIndex->MakeShadow();
  92. if ( _storage.SupportsShrinkFromFront() &&
  93. 0 != pMMergeLog )
  94. {
  95. //
  96. // Reload the master merge state including the split keys, etc.
  97. // This isn't quick, but it must be done since the target index
  98. // must be used to resolve queries because the current index
  99. // may already have been shrunk from the front.
  100. //
  101. ReloadMasterMerge( *pMMergeLog );
  102. }
  103. }
  104. CATCH( CException, e )
  105. {
  106. if ( 0 != _pCurrentMasterIndex )
  107. _pCurrentMasterIndex->MakeMaster();
  108. delete _pTargetMasterIndex;
  109. SCODE scE = e.GetErrorCode();
  110. if ( STATUS_INTEGER_DIVIDE_BY_ZERO == scE ||
  111. STATUS_ACCESS_VIOLATION == scE ||
  112. STATUS_IN_PAGE_ERROR == scE )
  113. {
  114. ciDebugOut(( DEB_ERROR,
  115. "Corrupt index or directory, caught 0x%x\n", scE ));
  116. _storage.ReportCorruptComponent( L"MasterMergeReload" );
  117. THROW( CException( CI_CORRUPT_DATABASE ) );
  118. }
  119. RETHROW();
  120. }
  121. END_CATCH
  122. } //CMasterMergeIndex
  123. //+---------------------------------------------------------------------------
  124. //
  125. // Member: CMasterMergeIndex::~CMasterMergeIndex, public
  126. //
  127. // Synopsis: Destructor for master index
  128. //
  129. // History: 30-Mar-94 DwightKr Created.
  130. //
  131. //----------------------------------------------------------------------------
  132. CMasterMergeIndex::~CMasterMergeIndex ()
  133. {
  134. delete _pIndSnap;
  135. if ( !IsZombie() )
  136. {
  137. //
  138. // We are Dismounting - must delete both.
  139. //
  140. delete _pCurrentMasterIndex;
  141. delete _pTargetMasterIndex;
  142. }
  143. else
  144. {
  145. //
  146. // If we are a zombie and being deleted, then some query
  147. // has responsibility for both the target and current master indexes
  148. // if they are non-null.
  149. //
  150. Win4Assert( !_pTargetMasterIndex || _pTargetMasterIndex->InUse() );
  151. #if 0
  152. //
  153. // We are not dismounting but are being deleted because either
  154. // the master merge ended or a query ended.
  155. //
  156. if ( _pCurrentMasterIndex && !_pCurrentMasterIndex->InUse() )
  157. {
  158. //
  159. // Since the refcount is 0, we have the responsibility to
  160. // destroy the current master index. This destruction is via
  161. // a query indexsnap shot which acquired this index while
  162. // a master merge was going on.
  163. //
  164. delete _pCurrentMasterIndex;
  165. }
  166. if ( _pTargetMasterIndex &&
  167. _pTargetMasterIndex->IsZombie() &&
  168. !_pTargetMasterIndex->InUse() )
  169. {
  170. //
  171. // The target master index is a zombie and it is not in use.
  172. // We must delete it. This can happen if there was a query(Q1)
  173. // in progress at the time Merge(M1) completed. Consider the
  174. // following sequence of events:
  175. // 0. Query Q1 starts and ref counts T1(Target Index of M1).
  176. // 1. M1 completes.
  177. // 2. A second merge M2 starts. It completes and zombifies
  178. // T1
  179. // 3. Q1 now is completing and so releases T1 whose ref.count
  180. // goes to 0. Hence we must delete it.
  181. //
  182. delete _pTargetMasterIndex;
  183. }
  184. #endif // 0
  185. }
  186. CleanupMMergeState();
  187. } //~CMasterMergeIndex
  188. //+---------------------------------------------------------------------------
  189. //
  190. // Member: CMasterMergeIndex::Fill public
  191. //
  192. // Synopsis: Returns a record describing the contents of this index.
  193. //
  194. // History: 30-Mar-94 DwightKr Created.
  195. //
  196. //----------------------------------------------------------------------------
  197. void CMasterMergeIndex::FillRecord ( CIndexRecord& record )
  198. {
  199. record._objectId = ObjectId();
  200. record._iid = GetId();
  201. record._type = itNewMaster;
  202. record._maxWorkId = MaxWorkId();
  203. }
  204. #if CIDBG == 1
  205. // useful for forcing a master merge to fail due to out of memory
  206. BOOL g_fFailMMOutOfMemory = FALSE;
  207. #endif // CIDBG == 1
  208. //+---------------------------------------------------------------------------
  209. //
  210. // Member: CMasterMergeIndex::Merge, public
  211. //
  212. // Synopsis: Merge index(es) into a new master index. This operation may
  213. // be restarted
  214. //
  215. // Effects: Fills the persistent index with data from the input
  216. // indexes.
  217. //
  218. // Arguments: [pNewKeyList] -- Keylist to merge (master merge only)
  219. // pFreshTest -- Fresh test to use for the merge. This
  220. // parameter must only be used - it cannot be
  221. // acquired by this routine.
  222. // [mergeProgress] -- % merge complete
  223. // [fGetRW] -- if TRUE, relevant words are computed
  224. // Currently ignored
  225. //
  226. // Requires: The index is initially empty.
  227. //
  228. // Notes: Every compressor is transacted.
  229. //
  230. // History: 15-May-91 KyleP Use new PutOccurrence() method.
  231. // 16-Apr-91 KyleP Created.
  232. // 17-Feb-93 KyleP Merge keylist
  233. // 30-Mar-94 DwightKr Copied here from CPersIndex, and added
  234. // restart capabilities.
  235. // 19-Apr-94 SrikantS Split key tracking changes and
  236. // initialization change.
  237. // 01-May-94 DwightKr Added code to allow for queries during
  238. // master merge.
  239. // 12-May-94 v-dlee Added relevant word computation
  240. // 29-Sep-94 SrikantS IndSnap ownership fix.
  241. // 25-Oct-95 DwightKr Add merge complete measurement
  242. //
  243. //----------------------------------------------------------------------------
  244. void CMasterMergeIndex::Merge(
  245. CWKeyList * pNewKeyList,
  246. CFreshTest * pFreshTest,
  247. const CPartition & partn,
  248. CCiFrmPerfCounter & mergeProgress,
  249. CCiFrameworkParams & frmwrkParams,
  250. BOOL fGetRW )
  251. {
  252. // Calculate max of all input widMax's
  253. Win4Assert( 0 != _pIndSnap );
  254. ciDebugOut(( DEB_ITRACE, "Master merge\n" ));
  255. #if CIDBG == 1
  256. unsigned cKey = 0;
  257. //
  258. // Assert that all the indexes in the snapshot are marked as
  259. // being in a master merge.
  260. //
  261. {
  262. unsigned cInd;
  263. CIndex ** apIndex;
  264. apIndex = _pIndSnap->LokGetIndexes( cInd );
  265. for ( unsigned i = 0; i < cInd; i++ )
  266. {
  267. Win4Assert( apIndex[i]->InMasterMerge() );
  268. }
  269. }
  270. #endif
  271. _pNewKeyList = pNewKeyList;
  272. Win4Assert( 0 != _pNewKeyList );
  273. Win4Assert( 0 != pFreshTest );
  274. WORKID widMax = _pIndSnap->MaxWorkId();
  275. ciDebugOut (( DEB_ITRACE, "Max work id %ld\n", widMax ));
  276. if ( MaxWorkId() != widMax )
  277. {
  278. Win4Assert( !"WidMax in MasterMergeIndex is Corrupt" );
  279. _storage.ReportCorruptComponent( L"MasterMergeIndex1" );
  280. THROW( CException( CI_CORRUPT_DATABASE ) );
  281. }
  282. //
  283. // Create and open the master merge log object so that the splitkeys can
  284. // be retrieved and stored.
  285. //
  286. PRcovStorageObj *pPersMMergeLog = _storage.QueryMMergeLog(_widMasterLog);
  287. SRcovStorageObj PersMMergeLog( pPersMMergeLog );
  288. ciFAILTEST( STATUS_NO_MEMORY );
  289. XPtr<CMMergeLog> xMMergeLog( new CMMergeLog( *pPersMMergeLog ) );
  290. //
  291. // STACKSTACK - cannot declare it where it is used because this is a
  292. // big object and we don't want to allocate inside the loop.
  293. //
  294. XPtr<CSplitKeyInfo> xSplitKeyInfo( new CSplitKeyInfo() );
  295. BOOL fReOpenTargetMaster = FALSE;
  296. TRY
  297. {
  298. //
  299. // Read-ahead on the source indexes results in better merge
  300. // performance, but slower queries. Temporarily switch modes.
  301. //
  302. CSetReadAhead readAhead( _storage );
  303. _pIndSnap->SetFreshTest( pFreshTest );
  304. //
  305. // Initialize and start/restart the master merge.
  306. //
  307. CKeyCursor * pKeySrc = StartMasterMerge( *_pIndSnap,
  308. xMMergeLog.GetReference(),
  309. _pNewKeyList );
  310. unsigned finalIndexSize = _pIndSnap->TotalSizeInPages();
  311. Win4Assert( finalIndexSize > 0 );
  312. finalIndexSize = max( 1, finalIndexSize ); // Prevent divide by 0
  313. mergeProgress.Update( _pTargetMasterIndex->GetIndex().PagesInUse() *
  314. 100 / finalIndexSize );
  315. CMergeSourceCursor pCurSrc( pKeySrc );
  316. BitOffset bitOffIndex; // BitOffset of a key in the target index
  317. Win4Assert( 0 != _pCompr );
  318. _pCompr->GetOffset( bitOffIndex );
  319. ULONG page; // for directory creation.
  320. if ( bitOffIndex.Offset() == 0 )
  321. page = bitOffIndex.Page() - 1;
  322. else
  323. page = bitOffIndex.Page();
  324. #if CIDBG==1
  325. GetTargetDir().SetBitOffsetLastAdded( page, bitOffIndex.Offset() );
  326. #endif // CIDBG==1
  327. if ( !pCurSrc.IsEmpty() )
  328. {
  329. #ifdef RELEVANT_WORDS_ENABLED
  330. //
  331. // Determine which wids are in use
  332. //
  333. UINT cWids = 0;
  334. WORKID * pwids = 0;
  335. SByteArray swids(0);
  336. {
  337. SFreshHash phash( *pFreshTest );
  338. cWids = phash->Count();
  339. pwids = new WORKID[cWids];
  340. swids.Set(pwids);
  341. CFreshHashIter freiter(*phash);
  342. for (UINT x = 0; !freiter.AtEnd(); freiter.Advance(), x++)
  343. pwids[x] = freiter->WorkId();
  344. }
  345. _SortULongArray((ULONG *) pwids,cWids);
  346. ciDebugOut (( DEB_ITRACE,"%d wids, %d through %d\n",
  347. cWids,pwids[0],pwids[cWids-1]));
  348. #endif // RELEVANT_WORDS_ENABLED
  349. //
  350. // Everytime we restart a master merge, we must use a brand
  351. // new split key - we must not use the old key for atomicity and
  352. // restartability
  353. //
  354. _pTrackIdxSplitKey->ClearNewKeyFound();
  355. #ifdef KEYLIST_ENABLED
  356. _pTrackKeyLstSplitKey->ClearNewKeyFound();
  357. #endif // KEYLIST_ENABLED
  358. BitOffset bitOffKeyLst;
  359. BitOffset StartBitOffset; // Starting loc in bitstream
  360. StartBitOffset.Init(0, 0);
  361. CKeyBuf *pKeyLast = new CKeyBuf; // initialized to min key
  362. SKeyBuf keyLast(pKeyLast);
  363. #if CIDBG == 1
  364. keyLast->SetPid(pidContents); // arbitrary but not pidAll
  365. WCHAR FirstLetter = '@';
  366. ciDebugOut (( DEB_ITRACE,"Merging. Merge on letter: "));
  367. #endif
  368. #ifdef RELEVANT_WORDS_ENABLED
  369. //
  370. // Create the relevant word computation object
  371. //
  372. CRelevantWord RelWord(pwids,cWids,defRWCount);
  373. swids.Acquire();
  374. delete pwids;
  375. pwids = 0;
  376. #endif // RELEVANT_WORDS_ENABLED
  377. //
  378. // Get checkpoint interval and convert # Kbytes to bits.
  379. //
  380. ULONG MasterMergeCheckpointInterval = frmwrkParams.GetMasterMergeCheckpointInterval() * 8 * 1024;
  381. ShrinkFromFront( _idxSplitKeyInfo.GetKey() );
  382. //
  383. // For each key found, add it and all wids and occurances to the
  384. // new master index.
  385. //
  386. for ( const CKeyBuf * pkey = pCurSrc->GetKey();
  387. pkey != NULL; pkey = pCurSrc->GetNextKey())
  388. {
  389. #if CIDBG == 1
  390. cKey++;
  391. if ( *(pkey->GetStr()) != FirstLetter )
  392. {
  393. FirstLetter = *(pkey->GetStr());
  394. if ( FirstLetter < L'~' )
  395. ciDebugOut(( DEB_NOCOMPNAME | DEB_ITRACE | DEB_PENDING, "%c",
  396. FirstLetter ));
  397. else
  398. ciDebugOut(( DEB_NOCOMPNAME | DEB_ITRACE | DEB_PENDING, "<%04x>",
  399. FirstLetter ));
  400. }
  401. #endif
  402. //
  403. // Don't store empty keys
  404. //
  405. WORKID wid = pCurSrc->WorkId();
  406. if ( wid == widInvalid )
  407. continue;
  408. //
  409. // Add the key to the new index.
  410. //
  411. _pCompr->PutKey(pkey, pCurSrc->WorkIdCount(), bitOffIndex);
  412. unsigned cWids = 0; // Count of wids for current key
  413. #ifdef RELEVANT_WORDS_ENABLED
  414. //
  415. // Can this possibly be a relevant word?
  416. //
  417. BOOL fPossibleRW = ((pkey->Pid() == pidContents) &&
  418. (((CKeyBuf * const) pkey)->IsPossibleRW()));
  419. #endif // RELEVANT_WORDS_ENABLED
  420. for ( ;
  421. wid != widInvalid;
  422. wid = pCurSrc->NextWorkId())
  423. {
  424. #if CIDBG == 1
  425. if ( g_fFailMMOutOfMemory )
  426. THROW( CException( E_OUTOFMEMORY ) );
  427. #endif // CIDBG == 1
  428. // fresh test
  429. CFreshTest::IndexSource is;
  430. is = pFreshTest->IsCorrectIndex(pCurSrc->IndexId(),wid);
  431. #if CIDBG==1
  432. if ( CFreshTest::Master == is )
  433. {
  434. Win4Assert( 0 != _pCurrentMasterIndex );
  435. if ( pCurSrc->IndexId() != _pCurrentMasterIndex->GetId() )
  436. ciDebugOut(( DEB_WARN,
  437. "src iid 0x%x, master iid 0x%x, target iid 0x%x\n",
  438. pCurSrc->IndexId(),
  439. _pCurrentMasterIndex->GetId(),
  440. _pTargetMasterIndex->GetId() ));
  441. Win4Assert( pCurSrc->IndexId() ==
  442. _pCurrentMasterIndex->GetId() );
  443. }
  444. #endif // CIDBG==1
  445. if ( is != CFreshTest::Invalid )
  446. {
  447. #ifdef RELEVANT_WORDS_ENABLED
  448. if ((is == CFreshTest::Shadow) && fPossibleRW)
  449. RelWord.Add(wid,pCurSrc->OccurrenceCount());
  450. #endif // RELEVANT_WORDS_ENABLED
  451. cWids++;
  452. _pCompr->PutWorkId(wid, pCurSrc->MaxOccurrence(), pCurSrc->OccurrenceCount());
  453. for (OCCURRENCE occ = pCurSrc->Occurrence();
  454. occ != OCC_INVALID;
  455. occ = pCurSrc->NextOccurrence())
  456. {
  457. _pCompr->PutOccurrence(occ);
  458. }
  459. }
  460. } // for workid
  461. //
  462. // Tell the splitkey object to remember the current position
  463. // if it is a splitkey candidate.
  464. //
  465. _pTrackIdxSplitKey->BeginNewKey( *pkey, bitOffIndex );
  466. #ifdef KEYLIST_ENABLED
  467. KEYID kid = _pNewKeyList->PutKey( pkey, bitOffKeyLst );
  468. #ifdef RELEVANT_WORDS_ENABLED
  469. //
  470. // Compute ranks and possibly add keyid as relevant word
  471. // for each wid containing the key
  472. //
  473. if (kid != kidInvalid && fPossibleRW)
  474. RelWord.DoneWithKey(kid,widMax,cWids);
  475. #endif // RELEVANT_WORDS_ENABLED
  476. _pTrackKeyLstSplitKey->BeginNewKey( *pkey,
  477. bitOffKeyLst,
  478. _pNewKeyList->MaxWorkId() );
  479. #else // !KEYLIST_ENABLED
  480. _pNewKeyList->AddKey();
  481. #endif // !KEYLIST_ENABLED
  482. //
  483. // Add directory entry, if necessary
  484. //
  485. if ( bitOffIndex.Page() != page )
  486. {
  487. page = bitOffIndex.Page();
  488. // Protect the directory and add the key
  489. CReleasableLock lock( _mutex,
  490. _storage.SupportsShrinkFromFront() );
  491. GetTargetDir().Add( bitOffIndex, *pkey );
  492. }
  493. else
  494. {
  495. #if CIDBG==1
  496. Win4Assert (
  497. page == GetTargetDir().GetBitOffsetLastAdded().Page()
  498. );
  499. #endif // CIDBG
  500. }
  501. *keyLast = *pkey;
  502. //
  503. // There's no point in special abort code. We have to handle
  504. // exceptions anyway.
  505. //
  506. ciFAILTEST( STATUS_DISK_FULL );
  507. if ( _fAbortMerge || partn.IsCleaningUp() )
  508. {
  509. ciDebugOut(( DEB_ITRACE, "Aborting Merge\n" ));
  510. _fAbortMerge=FALSE; // for next time around
  511. THROW( CException( STATUS_UNSUCCESSFUL ) );
  512. }
  513. //
  514. // Have we processed & written out MASTER_MERGE_INTERVAL bytes
  515. // to disk? If so, bring them online within the new master index
  516. // and remove them from the current master index as follows:
  517. //
  518. // 1. Take a lock to prevent further queries on pages from
  519. // the current master index.
  520. //
  521. // 2. Ask the _pNewMasterIndex for the highest key which
  522. // has made it do disk on the last page which itself
  523. // has also bee flushed to disk. This key is the
  524. // new split key.
  525. //
  526. // 3. Update the directory for the new master index.
  527. //
  528. // 4. Write the split key to the master log.
  529. //
  530. // 5. Shrink from front the current master index upto
  531. // but not including the lesser of the last page which
  532. // is in use by a query and the number of pages moved
  533. // to the new master index. Can't sff if there
  534. // are mapped sections, so free the stream first.
  535. //
  536. // 6. Release the lock
  537. //
  538. //
  539. if ( (bitOffIndex.Delta(StartBitOffset) > MasterMergeCheckpointInterval) &&
  540. _pTrackIdxSplitKey->IsNewKeyFound() )
  541. {
  542. // Step #1
  543. CLock lock( _mutex );
  544. //
  545. // Checkpoint our state to the master merge log.
  546. // Step #2
  547. //
  548. BitOffset flushBitOff;
  549. xSplitKeyInfo.GetReference() = _pTrackIdxSplitKey->GetSplitKey( flushBitOff );
  550. Win4Assert(
  551. CiPageToCommonPage( flushBitOff.Page()) >
  552. CiPageToCommonPage( xSplitKeyInfo->GetEndOffset().Page() )
  553. );
  554. //
  555. // Flush all the pages upto and including the "flushBitOff".
  556. // This will guarantee that the page containing the split
  557. // key will never be touched again.
  558. //
  559. _pTargetSink->Flush( TRUE );
  560. xMMergeLog->SetIdxSplitKeyInfo( xSplitKeyInfo->GetKey(),
  561. xSplitKeyInfo->GetBeginOffset(),
  562. xSplitKeyInfo->GetEndOffset() );
  563. //
  564. // Step #3
  565. //
  566. GetTargetDir().LokFlushDir( xSplitKeyInfo->GetKey() );
  567. #ifdef KEYLIST_ENABLED
  568. //
  569. // If we have a split key for the key list, then we should
  570. // go ahead and flush it.
  571. //
  572. const CSplitKeyInfo & keylstSplitKey =
  573. _pTrackKeyLstSplitKey->GetSplitKey( flushBitOff );
  574. if ( _pTrackKeyLstSplitKey->IsNewKeyFound() )
  575. {
  576. _pNewKeyList->Flush();
  577. xMMergeLog->SetKeyListSplitKeyInfo(
  578. keylstSplitKey.GetKey(),
  579. keylstSplitKey.GetBeginOffset(),
  580. keylstSplitKey.GetEndOffset() );
  581. xMMergeLog->SetKeyListWidMax( keylstSplitKey.GetWidMax() );
  582. _pTrackKeyLstSplitKey->ClearNewKeyFound();
  583. }
  584. #else // !KEYLIST_ENABLED
  585. xMMergeLog->SetKeyListWidMax( _pNewKeyList->MaxWorkId() );
  586. #endif // !KEYLIST_ENABLED
  587. // Step #4
  588. //
  589. xMMergeLog->CheckPoint();
  590. //
  591. // Step #4.5
  592. //
  593. _idxSplitKeyInfo = xSplitKeyInfo.GetReference();
  594. //
  595. // Step #5
  596. //
  597. if ( 0 != _pCurrentMasterIndex )
  598. {
  599. pCurSrc->FreeStream();
  600. ShrinkFromFront( xSplitKeyInfo->GetKey() );
  601. pCurSrc->RefillStream();
  602. }
  603. //
  604. // Mark that we have used up this split key.
  605. //
  606. _pTrackIdxSplitKey->ClearNewKeyFound();
  607. //
  608. // Step #6
  609. //
  610. StartBitOffset = bitOffIndex;
  611. //
  612. // Update the size in the new master index.
  613. //
  614. _pTargetMasterIndex->GetIndex().UpdatePageCount( *_pTargetSink );
  615. //
  616. // Write the new % complete for the merge
  617. //
  618. mergeProgress.Update( _pTargetMasterIndex->GetIndex().PagesInUse() *
  619. 100 /
  620. finalIndexSize );
  621. } // checkpoint
  622. } // for key
  623. #ifdef RELEVANT_WORDS_ENABLED
  624. _pRWStore = RelWord.AcquireStore();
  625. ciDebugOut (( DEB_ITRACE,"grabbing _pRWStore: %lx\n",_pRWStore));
  626. #endif // RELEVANT_WORDS_ENABLED
  627. ciDebugOut(( DEB_ITRACE | DEB_PENDING, "%d keys in index\n", cKey ));
  628. }
  629. CKeyBuf *pKeyMax = new CKeyBuf;
  630. SKeyBuf sKeyMax(pKeyMax);
  631. sKeyMax->FillMax();
  632. sKeyMax->SetPid(pidContents);
  633. BOOL fMaxKeyAddedNow = FALSE;
  634. BitOffset bitOffEnd;
  635. if ( !_pCompr->IsAtSentinel() )
  636. {
  637. // add sentinel key
  638. _pCompr->PutKey(pKeyMax, 1, bitOffIndex);
  639. _pCompr->GetOffset( bitOffEnd );
  640. fMaxKeyAddedNow = TRUE;
  641. }
  642. CLock lock( _mutex );
  643. //
  644. // Destroy the compressor, etc and clean up the master merge state.
  645. //
  646. _pCompr->FreeStream();
  647. CleanupMMergeState();
  648. //
  649. // The compressor must be destroyed before we do the final flush.
  650. // O/W, the last page (which is being used by the compressor) will
  651. // not get flushed. We cannot update the directory and the master
  652. // merge state until the index data is written out to disk.
  653. //
  654. _pTargetSink->Flush();
  655. ciFAILTEST( STATUS_LOG_FILE_FULL );
  656. if ( fMaxKeyAddedNow )
  657. {
  658. if ( page != bitOffIndex.Page() )
  659. {
  660. ciDebugOut(( DEB_ITRACE,
  661. "Adding max key to directory. Page:0x%X Offset:0x%X\n",
  662. bitOffIndex.Page(), bitOffIndex.Offset() ));
  663. GetTargetDir().Add( bitOffIndex, *pKeyMax );
  664. }
  665. GetTargetDir().LokFlushDir( *pKeyMax );
  666. GetTargetDir().LokBuildDir( *pKeyMax );
  667. xSplitKeyInfo->SetBeginOffset(bitOffIndex);
  668. xSplitKeyInfo->SetEndOffset(bitOffEnd);
  669. xSplitKeyInfo->SetKey( *pKeyMax );
  670. ciFAILTEST( STATUS_LOG_FILE_FULL );
  671. xMMergeLog->SetIdxSplitKeyInfo( xSplitKeyInfo->GetKey(),
  672. xSplitKeyInfo->GetBeginOffset(),
  673. xSplitKeyInfo->GetEndOffset() );
  674. xMMergeLog->CheckPoint();
  675. ciFAILTEST( STATUS_LOG_FILE_FULL );
  676. //
  677. // The in-memory split key information MUST be updated ONLY
  678. // after the checkpoint to disk is succesfully done.
  679. //
  680. _idxSplitKeyInfo = xSplitKeyInfo.GetReference();
  681. }
  682. _pTargetSink->ShrinkToFit();
  683. _pTargetMasterIndex->GetIndex().UpdatePageCount( *_pTargetSink );
  684. delete _pTargetSink;
  685. _pTargetSink = 0;
  686. //
  687. // No need to reopen the stream as read-only if the stream supports
  688. // SFF, since we need to leave it as writable for the next master
  689. // merge anyway.
  690. //
  691. if ( !_storage.SupportsShrinkFromFront() )
  692. {
  693. fReOpenTargetMaster = TRUE;
  694. _pTargetMasterIndex->GetIndex().Reopen( FALSE );
  695. fReOpenTargetMaster = FALSE;
  696. }
  697. //
  698. // The merge is 100% complete.
  699. //
  700. mergeProgress.Update( 100 );
  701. }
  702. CATCH( CException, e )
  703. {
  704. _pIndSnap->ResetFreshTest();
  705. //
  706. // The CMasterMerge object owns the key list. We should 0 it
  707. // to prevent having dangling references.
  708. //
  709. _pNewKeyList = 0;
  710. CleanupMMergeState();
  711. delete _pTargetSink;
  712. _pTargetSink = 0;
  713. if ( fReOpenTargetMaster )
  714. _pTargetMasterIndex->GetIndex().Reopen( _storage.SupportsShrinkFromFront() );
  715. // Really bad errors indicate the index is corrupt.
  716. SCODE scE = e.GetErrorCode();
  717. if ( STATUS_INTEGER_DIVIDE_BY_ZERO == scE ||
  718. STATUS_ACCESS_VIOLATION == scE ||
  719. STATUS_IN_PAGE_ERROR == scE )
  720. {
  721. ciDebugOut(( DEB_ERROR,
  722. "Corrupt index or directory, caught 0x%x\n", scE ));
  723. _storage.ReportCorruptComponent( L"MasterMerge" );
  724. THROW( CException( CI_CORRUPT_DATABASE ) );
  725. }
  726. RETHROW();
  727. }
  728. END_CATCH
  729. _pIndSnap->ResetFreshTest();
  730. _pNewKeyList = 0;
  731. #ifdef KEYLIST_ENABLED
  732. pNewKeyList->Done( _fAbortMerge );
  733. #endif // KEYLIST_ENABLED
  734. ciDebugOut(( DEB_ITRACE, "Master merge complete\n" ));
  735. } //Merge
  736. //+---------------------------------------------------------------------------
  737. //
  738. // Member: CMasterMergeIndex::Reload, private
  739. //
  740. // Synopsis: Restores the data for the split keys used for during a
  741. // master merge as well as the index directory.
  742. //
  743. // History: 25-Apr-94 DwightKr Copied from StartMasterMerge
  744. // 23-Aug-94 SrikantS Moved from CMasterMergeIndex
  745. //
  746. //----------------------------------------------------------------------------
  747. void CMasterMergeIndex::ReloadMasterMerge( CMMergeLog & mMergeLog )
  748. {
  749. Win4Assert( 0 != _pTargetMasterIndex );
  750. Win4Assert( !_fStateLoaded );
  751. //
  752. // Index Split Key tracking variables.
  753. //
  754. CKeyBuf * pIdxSplitKey = new CKeyBuf();
  755. SKeyBuf idxSplitKey(pIdxSplitKey);
  756. idxSplitKey->FillMin();
  757. BitOffset idxBeginBitOff;
  758. idxBeginBitOff.Init(0,0);
  759. BitOffset idxEndBitOff;
  760. idxEndBitOff.Init(0,0);
  761. mMergeLog.GetIdxSplitKeyInfo( *pIdxSplitKey,
  762. idxBeginBitOff,
  763. idxEndBitOff );
  764. RestoreIndexDirectory( *pIdxSplitKey, MaxWorkId(), idxEndBitOff );
  765. ciDebugOut (( DEB_ITRACE, "widMax passed to compressor: %ld\n", MaxWorkId() ));
  766. _pTargetMasterIndex->GetIndex().SetUsedPagesCount( idxEndBitOff.Page() + 1 );
  767. _idxSplitKeyInfo.SetBeginOffset(idxBeginBitOff);
  768. _idxSplitKeyInfo.SetEndOffset(idxEndBitOff);
  769. _idxSplitKeyInfo.SetKey( *pIdxSplitKey );
  770. _fStateLoaded = TRUE;
  771. } //ReloadMasterMerge
  772. //+---------------------------------------------------------------------------
  773. //
  774. // Member: CMasterMergeIndex::StartMasterMerge, private
  775. //
  776. // Synopsis: Initializes the merge cursor used to merge the source
  777. // indexes.
  778. //
  779. // Arguments: [indSnap] -- array of indexes to be merged
  780. // [mMergeLog] -- master merge log
  781. // [pNewKeyList] -- keyList to update with missing keys
  782. //
  783. // History: 20-Apr-94 SrikantS Created
  784. // 25-Apr-94 DwightKr Moved some functionality to
  785. // ReloadMasterMerge()
  786. //
  787. //----------------------------------------------------------------------------
  788. CKeyCursor *
  789. CMasterMergeIndex::StartMasterMerge( CIndexSnapshot & indSnap,
  790. CMMergeLog & mMergeLog,
  791. CWKeyList * pNewKeyList )
  792. {
  793. //
  794. // Create the target index sink for write access.
  795. //
  796. ciFAILTEST( CI_CORRUPT_DATABASE );
  797. //
  798. // In user mode, we have to Restore the mastermerge start if it is not
  799. // already restored.
  800. //
  801. if ( !_fStateLoaded )
  802. {
  803. ciDebugOut(( DEB_ITRACE, "Reloading MasterMergeState\n" ));
  804. ReloadMasterMerge( mMergeLog );
  805. }
  806. CPhysIndex & idx = _pTargetMasterIndex->GetIndex();
  807. PMmStream * stream = idx.DupReadWriteStream( PStorage::eOpenForWrite );
  808. XPtr<PMmStream> sStream(stream);
  809. _pTargetSink = new CPhysIndex( idx,
  810. PStorage::eOpenForWrite,
  811. sStream );
  812. _pTargetSink->SetPageGrowth( EIGHT_MEGABYTES / CI_PAGE_SIZE );
  813. #if CIDBG == 1
  814. if ( _idxSplitKeyInfo.GetEndOffset().Page() != 0 )
  815. {
  816. ULONG * pul = _pTargetSink->BorrowBuffer( _idxSplitKeyInfo.GetEndOffset().Page() );
  817. Win4Assert( 0 != *pul );
  818. _pTargetSink->ReturnBuffer( _idxSplitKeyInfo.GetEndOffset().Page() );
  819. }
  820. #endif
  821. //
  822. // Delete all the keys in the directory after the split key.
  823. //
  824. {
  825. //
  826. // Must serialize access to the B_Tree when we are making
  827. // structural modifications to it.
  828. //
  829. CLock lock( _mutex );
  830. GetTargetDir().DeleteKeysAfter( _idxSplitKeyInfo.GetKey() );
  831. }
  832. //
  833. // If we are restarting a 'paused' master merge, then restore the
  834. // persistent decompressor to its previous state. Else, just
  835. // build a decompressor and initialize it state to start at the
  836. // front of the physical index.
  837. //
  838. Win4Assert( !_pTrackIdxSplitKey );
  839. ciFAILTEST( STATUS_NO_MEMORY );
  840. _pTrackIdxSplitKey = new CTrackSplitKey( _idxSplitKeyInfo.GetKey(),
  841. _idxSplitKeyInfo.GetBeginOffset(),
  842. _idxSplitKeyInfo.GetEndOffset() );
  843. ciFAILTEST( STATUS_NO_MEMORY );
  844. _pCompr = new CPersComp( *_pTargetSink,
  845. MaxWorkId(),
  846. _idxSplitKeyInfo.GetEndOffset(),
  847. _idxSplitKeyInfo.GetBeginOffset(),
  848. _idxSplitKeyInfo.GetKey() );
  849. _pTargetSink->SetUsedPagesCount( _idxSplitKeyInfo.GetEndOffset().Page() + 1 );
  850. //
  851. // Build the merge cursor and position it at the key just after the
  852. // split key. If a master merge is NOT being restarted, this
  853. // positions the merge cursor at the first key.
  854. //
  855. ciFAILTEST( STATUS_NO_MEMORY );
  856. CMergeSourceCursor pCurSrc ( indSnap, &_idxSplitKeyInfo.GetKey() );
  857. if ( pCurSrc.IsEmpty() )
  858. {
  859. ciDebugOut (( DEB_ITRACE, "No merge cursor created\n" ));
  860. return(0);
  861. }
  862. ciDebugOut(( DEB_ITRACE, "widMax passed to compressor: %ld\n",
  863. MaxWorkId() ));
  864. if ( !_idxSplitKeyInfo.GetKey().IsMinKey() )
  865. {
  866. Win4Assert( AreEqual(pCurSrc->GetKey(), &_idxSplitKeyInfo.GetKey()) );
  867. ciFAILTEST( CI_CORRUPT_DATABASE );
  868. pCurSrc->GetNextKey();
  869. }
  870. #ifdef KEYLIST_ENABLED
  871. //
  872. // Setup the keylist splitKey tracking variables.
  873. //
  874. ciFAILTEST( STATUS_NO_MEMORY );
  875. CKeyBuf * pKeylstSplitKey = new CKeyBuf();
  876. SKeyBuf keylstSplitKey(pKeylstSplitKey);
  877. keylstSplitKey->FillMin();
  878. BitOffset keylstBeginBitOff;
  879. keylstBeginBitOff.Init(0,0);
  880. BitOffset keylstEndBitOff;
  881. keylstEndBitOff.Init(0,0);
  882. mMergeLog.GetKeyListSplitKeyInfo( *pKeylstSplitKey,
  883. keylstBeginBitOff,
  884. keylstEndBitOff );
  885. //
  886. // Flag set to TRUE if the keylist split key is > the index list split
  887. // key.
  888. //
  889. BOOL fKLSplitKeyBigger = FALSE;
  890. if ( _idxSplitKeyInfo.GetKey().IsMinKey() ||
  891. pKeylstSplitKey->Compare( _idxSplitKeyInfo.GetKey() ) > 0 )
  892. {
  893. *pKeylstSplitKey = _idxSplitKeyInfo.GetKey();
  894. fKLSplitKeyBigger = TRUE;
  895. }
  896. Win4Assert( _pTrackIdxSplitKey );
  897. RestoreKeyListDirectory( _idxSplitKeyInfo.GetKey(),
  898. MaxWorkId(),
  899. pNewKeyList,
  900. *pKeylstSplitKey );
  901. Win4Assert( !_pTrackKeyLstSplitKey );
  902. ciFAILTEST( STATUS_NO_MEMORY );
  903. if ( !fKLSplitKeyBigger )
  904. {
  905. _pTrackKeyLstSplitKey = new CTrackSplitKey( *pKeylstSplitKey,
  906. keylstBeginBitOff,
  907. keylstEndBitOff
  908. );
  909. }
  910. else
  911. {
  912. //
  913. // Just set it to be the min key with 0,0 .
  914. //
  915. _pTrackKeyLstSplitKey = new CTrackSplitKey();
  916. }
  917. #endif // KEYLIST_ENABLED
  918. return pCurSrc.Acquire();
  919. } //StartMasterMerge
  920. //+---------------------------------------------------------------------------
  921. //
  922. // Member: CMasterMergeIndex::CleanupMMergeState, private
  923. //
  924. // Synopsis: Free all memory resources used for this master merge.
  925. //
  926. // History: 20-Apr-94 SrikantS Created
  927. //
  928. //----------------------------------------------------------------------------
  929. void CMasterMergeIndex::CleanupMMergeState()
  930. {
  931. //
  932. // We will create safe pointers instead of calling delete because we
  933. // want to be able to cope with exceptions thrown in the destructors
  934. // also.
  935. //
  936. #ifdef KEYLIST_ENABLED
  937. delete _pTrackKeyLstSplitKey;
  938. _pTrackKeyLstSplitKey = 0;
  939. #endif // KEYLIST_ENABLED
  940. delete _pTrackIdxSplitKey;
  941. _pTrackIdxSplitKey = 0;
  942. // If the stream is still unflushed in the compressor, it isn't
  943. // guaranteed to be flushed by this destructor. This destructor will
  944. // not fail for any reason including failure to flush, so don't rely
  945. // on this in success code paths.
  946. delete _pCompr;
  947. _pCompr = 0;
  948. } //CleanupMMergeState
  949. //+---------------------------------------------------------------------------
  950. //
  951. // Member: CMasterMergeIndex::ShrinkFromFront, private
  952. //
  953. // Synopsis: Shrinks the index, from the front, to release the disk
  954. // associated with the space before the split key.
  955. //
  956. // Parameters: [keyBuf] -- contents of last key which can be deleted
  957. // from the current master index
  958. //
  959. // History: 01-Aug-94 DwightKr Created
  960. //
  961. //----------------------------------------------------------------------------
  962. void CMasterMergeIndex::ShrinkFromFront( const CKeyBuf & keyBuf )
  963. {
  964. //
  965. // If there is no current master index, we have nothing to shrink
  966. //
  967. if ( !_pCurrentMasterIndex )
  968. return;
  969. //
  970. // Locate the page # of the key in the OFS btree which can be used
  971. // to locate this splitkey. On a restart, the merge will seek
  972. // to the key which is the nearest key less than the split
  973. // key stored in the OFS btree. Hence, we need to get the offset of
  974. // the key in the OFS btree which is equal to or less than the splitkey.
  975. // This offset is returned by the COfsdir Seek method.
  976. //
  977. BitOffset offset;
  978. _pCurrentMasterIndex->GetDirectory().Seek( keyBuf, 0, offset );
  979. ULONG ulFirstPageInUse = offset.Page();
  980. ULONG ulMinPageInCache = MAXULONG;
  981. if ( _pCurrentMasterIndex->GetIndex().MinPageInUse( ulMinPageInCache ) )
  982. {
  983. //
  984. // The cache has some pages in it and so we must take the minimum
  985. // of the cache page and the directory.
  986. //
  987. Win4Assert( MAXULONG != ulMinPageInCache );
  988. ulFirstPageInUse = min( ulFirstPageInUse, ulMinPageInCache );
  989. }
  990. else
  991. {
  992. //
  993. // The cache is empty implying that there none of the pages from
  994. // the current master are in use. We must have exhausted all the
  995. // keys from the current master.
  996. //
  997. }
  998. //
  999. // If we can't decommit any pages because they are all in use, then get
  1000. // out now.
  1001. //
  1002. Win4Assert( ulFirstPageInUse >= _ulFirstPageInUse );
  1003. ULONG numPages = ulFirstPageInUse - _ulFirstPageInUse;
  1004. if ( numPages > 0 )
  1005. _ulFirstPageInUse += _pCurrentMasterIndex->ShrinkFromFront( _ulFirstPageInUse,
  1006. numPages );
  1007. } //ShrinkFromFront
  1008. //+---------------------------------------------------------------------------
  1009. //
  1010. // Member: CMasterMergeIndex::QueryCursor, public
  1011. //
  1012. // Synopsis: Return a cursor for the master index during master merge
  1013. //
  1014. // Returns: A new cursor.
  1015. //
  1016. // History: 24-Apr-91 KyleP Created.
  1017. // 30-Mar-94 DwightKr Copied here from CPersIndex
  1018. //
  1019. //----------------------------------------------------------------------------
  1020. CKeyCursor * CMasterMergeIndex::QueryCursor()
  1021. {
  1022. CKey key;
  1023. key.FillMin();
  1024. return QueryKeyCursor( &key );
  1025. }
  1026. //+---------------------------------------------------------------------------
  1027. //
  1028. // Member: CMasterMergeIndex::QuerySplitCursor, private
  1029. //
  1030. // Synopsis: Return a cursor for the logical master index during master
  1031. // merge
  1032. //
  1033. // Returns: A new cursor.
  1034. //
  1035. // History: 30-Mar-94 DwightKr Created
  1036. //
  1037. // Notes: Three cases of interest can be found during a master merge:
  1038. //
  1039. // 1. Master merge for the first time, no 'current master index'
  1040. // hence we return a null for the cursor to the master index.
  1041. //
  1042. // 2. Master merge hasn't written a split key as yet, return a
  1043. // cursor to decompress the 'current master index'.
  1044. //
  1045. // 3. All other cases, build a cursor to decompress and span
  1046. // both the 'current master index' and the 'new master index.'
  1047. //
  1048. //----------------------------------------------------------------------------
  1049. CKeyCursor * CMasterMergeIndex::QuerySplitCursor(const CKey * pKey)
  1050. {
  1051. if ( 0 == _pCurrentMasterIndex )
  1052. return 0;
  1053. // Take the lock if the volume supports shrink from front
  1054. CReleasableLock lock( _mutex, _storage.SupportsShrinkFromFront() );
  1055. if ( _storage.SupportsShrinkFromFront() &&
  1056. !_idxSplitKeyInfo.GetKey().IsMinKey() )
  1057. {
  1058. return new CMPersDeComp( _pCurrentMasterIndex->GetDirectory(),
  1059. _pCurrentMasterIndex->GetId(),
  1060. _pCurrentMasterIndex->GetIndex(),
  1061. _pCurrentMasterIndex->MaxWorkId(),
  1062. GetTargetDir(),
  1063. GetId(),
  1064. _pTargetMasterIndex->GetIndex(),
  1065. pKey,
  1066. MaxWorkId(),
  1067. _idxSplitKeyInfo,
  1068. _mutex );
  1069. }
  1070. else
  1071. {
  1072. //
  1073. // Don't use the split cursor. The current master index is valid.
  1074. //
  1075. BitOffset posKey;
  1076. CKeyBuf keyInit;
  1077. _pCurrentMasterIndex->GetDirectory().Seek( *pKey,
  1078. &keyInit,
  1079. posKey );
  1080. return new CPersDeComp( _pCurrentMasterIndex->GetDirectory(),
  1081. _pCurrentMasterIndex->GetId(),
  1082. _pCurrentMasterIndex->GetIndex(),
  1083. posKey,
  1084. keyInit,
  1085. pKey,
  1086. _pCurrentMasterIndex->MaxWorkId() );
  1087. }
  1088. } //QuerySplitCursor
  1089. //+---------------------------------------------------------------------------
  1090. //
  1091. // Member: CMasterMergeIndex::QueryKeyCursor, public
  1092. //
  1093. // Synopsis: Return a key cursor for the master index when restarting a
  1094. // master merge
  1095. //
  1096. // Returns: A new cursor.
  1097. //
  1098. // History: 12-Apr-94 DwightKr Created.
  1099. //
  1100. //----------------------------------------------------------------------------
  1101. CKeyCursor * CMasterMergeIndex::QueryKeyCursor(const CKey * pKey)
  1102. {
  1103. // Take the lock if the volume supports shrink from front
  1104. CReleasableLock lock( _mutex, _storage.SupportsShrinkFromFront() );
  1105. XPtr<CKeyCursor> xCursor( QuerySplitCursor( pKey ) );
  1106. if ( !xCursor.IsNull() && (xCursor->GetKey() == 0) )
  1107. xCursor.Free();
  1108. return xCursor.Acquire();
  1109. } //QueryKeyCursor
  1110. //+---------------------------------------------------------------------------
  1111. //
  1112. // Member: CMasterMergeIndex::QueryCursor, public
  1113. //
  1114. // Synopsis: Return a cursor for the master index during master merge
  1115. //
  1116. // Arguments: [pkey] -- Key to initially seek for.
  1117. // [isRange] -- TRUE for range query
  1118. // [cMaxNodes] -- Max node (key) count
  1119. //
  1120. // Returns: A new cursor.
  1121. //
  1122. // History: 24-Apr-91 KyleP Created.
  1123. // 30-Mar-94 DwightKr Copied here from CPersIndex and
  1124. // modified to span multiple masters
  1125. //
  1126. //----------------------------------------------------------------------------
  1127. COccCursor * CMasterMergeIndex::QueryCursor( const CKey * pKey,
  1128. BOOL isRange,
  1129. ULONG & cMaxNodes )
  1130. {
  1131. Win4Assert( cMaxNodes > 0 );
  1132. if (isRange)
  1133. {
  1134. CKey keyEnd;
  1135. keyEnd.FillMax (*pKey);
  1136. return QueryRangeCursor( pKey, &keyEnd, cMaxNodes );
  1137. }
  1138. if (pKey->Pid() == pidAll)
  1139. return QueryRangeCursor( pKey, pKey, cMaxNodes );
  1140. cMaxNodes--;
  1141. if ( 0 == cMaxNodes )
  1142. {
  1143. ciDebugOut(( DEB_WARN, "Node limit reached in CMasterMergeIndex::QueryCursor.\n" ));
  1144. THROW( CException( STATUS_TOO_MANY_NODES ) );
  1145. }
  1146. XPtr<CKeyCursor> xCursor( QuerySplitCursor( pKey ) );
  1147. if ( ( !xCursor.IsNull() ) &&
  1148. ( xCursor->GetKey() == 0
  1149. || !pKey->MatchPid (*xCursor->GetKey())
  1150. || pKey->CompareStr(*xCursor->GetKey()) != 0 )
  1151. )
  1152. {
  1153. xCursor.Free();
  1154. }
  1155. return xCursor.Acquire();
  1156. } //QueryCursor
  1157. //+---------------------------------------------------------------------------
  1158. //
  1159. // Member: CMasterMergeIndex::QueryRangeCursor, public
  1160. //
  1161. // Synopsis: Return a range cursor for the master index during master merge
  1162. //
  1163. // Arguments: [pkey] -- Key at beginning of the range.
  1164. // [pKeyEnd] -- Key at the end of the range.
  1165. // [cMaxNodes] -- Max node (key) count
  1166. //
  1167. // Returns: A new cursor.
  1168. //
  1169. // History: 11-Dec-91 AmyA Created.
  1170. // 31-Jan-92 AmyA Moved code to CreateRange().
  1171. // 30-Mar-94 DwightKr Copied here from CPersIndex and
  1172. // modified to span multiple masters
  1173. //
  1174. //----------------------------------------------------------------------------
  1175. COccCursor * CMasterMergeIndex::QueryRangeCursor( const CKey * pkey,
  1176. const CKey * pKeyEnd,
  1177. ULONG & cMaxNodes )
  1178. {
  1179. Win4Assert( cMaxNodes > 0 );
  1180. COccCurStack curStk;
  1181. // Take the lock if the volume supports shrink from front
  1182. CReleasableLock lock( _mutex, _storage.SupportsShrinkFromFront() );
  1183. CreateRange( curStk, pkey, pKeyEnd, cMaxNodes );
  1184. return curStk.QuerySynCursor( MaxWorkId() );
  1185. } //QueryRangeCursor
  1186. //+---------------------------------------------------------------------------
  1187. //
  1188. // Member: CMasterMergeIndex::QuerySynCursor, public
  1189. //
  1190. // Synopsis: Return a synonym cursor for master index during master merge
  1191. //
  1192. // Arguments: [keyStk] -- Stack of keys to be searched for.
  1193. // [isRange] -- Whether or not this is a range search.
  1194. // [cMaxNodes] -- Max node (key) count
  1195. //
  1196. // Returns: A new cursor.
  1197. //
  1198. // History: 31-Jan-92 AmyA Created.
  1199. // 30-Mar-94 DwightKr Copied here from CPersIndex and
  1200. // modified to span multiple masters
  1201. //
  1202. //----------------------------------------------------------------------------
  1203. COccCursor * CMasterMergeIndex::QuerySynCursor( CKeyArray & keyArr,
  1204. BOOL isRange,
  1205. ULONG & cMaxNodes )
  1206. {
  1207. Win4Assert( cMaxNodes > 0 );
  1208. if ( 0 == _pCurrentMasterIndex )
  1209. return 0;
  1210. COccCurStack curStk;
  1211. int keyCount = keyArr.Count();
  1212. // Take the lock if the volume supports shrink from front
  1213. CReleasableLock lock( _mutex, _storage.SupportsShrinkFromFront() );
  1214. for (int i = 0; i < keyCount; i++)
  1215. {
  1216. CKey& key = keyArr.Get(i);
  1217. if (isRange)
  1218. {
  1219. CKey keyEnd;
  1220. keyEnd.FillMax(key);
  1221. CreateRange( curStk, &key, &keyEnd, cMaxNodes );
  1222. }
  1223. else if ( key.Pid() == pidAll )
  1224. {
  1225. CreateRange ( curStk, &key, &key, cMaxNodes );
  1226. }
  1227. else
  1228. {
  1229. cMaxNodes--;
  1230. if ( 0 == cMaxNodes )
  1231. {
  1232. ciDebugOut(( DEB_WARN, "Node limit reached in CMasterMergeIndex::QuerySynCursor.\n" ));
  1233. THROW( CException( STATUS_TOO_MANY_NODES ) );
  1234. }
  1235. BitOffset posKey;
  1236. if ( _storage.SupportsShrinkFromFront() &&
  1237. key.CompareStr( _idxSplitKeyInfo.GetKey() ) <= 0 )
  1238. GetTargetDir().Seek ( key, 0, posKey );
  1239. else
  1240. _pCurrentMasterIndex->GetDirectory().Seek ( key, 0, posKey );
  1241. XPtr<CKeyCursor> xCursor( QuerySplitCursor( &key ) );
  1242. curStk.Push( xCursor.GetPointer() );
  1243. xCursor.Acquire();
  1244. }
  1245. }
  1246. return curStk.QuerySynCursor( MaxWorkId() );
  1247. } //QuerySynCursor
  1248. //+---------------------------------------------------------------------------
  1249. //
  1250. // Member: CMasterMergeIndex::CreateRange, private
  1251. //
  1252. // Synopsis: Adds all cursors with keys between pkey and pKeyEnd to curStk.
  1253. //
  1254. // Arguments: [curStk] -- CKeyCurStack to add cursors to.
  1255. // [pkey] -- Key at beginning of range.
  1256. // [pKeyEnd] -- End of key range.
  1257. // [cMaxNodes] -- Max node (key) count
  1258. //
  1259. // History: 31-Jan-92 AmyA Created.
  1260. // 30-Mar-94 DwightKr Copied here from CPersIndex and
  1261. // modified to span multiple masters
  1262. //
  1263. //----------------------------------------------------------------------------
  1264. void CMasterMergeIndex::CreateRange( COccCurStack & curStk,
  1265. const CKey * pKeyStart,
  1266. const CKey * pKeyEnd,
  1267. ULONG & cMaxNodes )
  1268. {
  1269. Win4Assert( cMaxNodes > 0 );
  1270. cMaxNodes--;
  1271. if ( 0 == cMaxNodes )
  1272. {
  1273. ciDebugOut(( DEB_WARN, "Node limit reached in CPersIndex::CreateRange.\n" ));
  1274. THROW( CException( STATUS_TOO_MANY_NODES ) );
  1275. }
  1276. CKeyCursor * pCursor = QuerySplitCursor( pKeyStart );
  1277. if ( !pCursor )
  1278. return;
  1279. XPtr<CCursor> xCursor( pCursor );
  1280. const CKeyBuf * pKeyCurrent = pCursor->GetKey();
  1281. if ( 0 == pKeyCurrent )
  1282. return;
  1283. PROPID pid = pKeyStart->Pid();
  1284. curStk.Push(pCursor);
  1285. xCursor.Acquire();
  1286. ciDebugOut(( DEB_ITRACE, "First key %.*ws, pid %d\n",
  1287. pKeyCurrent->StrLen(), pKeyCurrent->GetStr(), pKeyCurrent->Pid() ));
  1288. do
  1289. {
  1290. if (pid != pidAll) // exact pid match
  1291. {
  1292. // skip wrong pids
  1293. while (pid != pKeyCurrent->Pid())
  1294. {
  1295. #if CIDBG == 1 //------------------------------------------
  1296. if (pKeyCurrent)
  1297. {
  1298. ciDebugOut(( DEB_ITRACE, " skip: %.*ws, pid %d, wid %d\n",
  1299. pKeyCurrent->StrLen(),
  1300. pKeyCurrent->GetStr(),
  1301. pKeyCurrent->Pid(),
  1302. pCursor->WorkId() ));
  1303. }
  1304. else
  1305. ciDebugOut(( DEB_ITRACE, " <NULL> key\n" ));
  1306. #endif //--------------------------------------------------
  1307. pKeyCurrent = pCursor->GetNextKey();
  1308. if (pKeyCurrent == 0
  1309. || pKeyEnd->CompareStr(*pKeyCurrent) < 0 )
  1310. break;
  1311. }
  1312. // either pid matches or we have overshot
  1313. // i.e. different pids and current string > end
  1314. }
  1315. if (pKeyCurrent == 0 || !pKeyEnd->MatchPid(*pKeyCurrent)
  1316. || pKeyEnd->CompareStr (*pKeyCurrent) < 0 )
  1317. {
  1318. break; // <--- LOOP EXIT
  1319. }
  1320. cMaxNodes--;
  1321. if ( 0 == cMaxNodes )
  1322. {
  1323. ciDebugOut(( DEB_WARN, "Node limit reached in CPersIndex::CreateRange.\n" ));
  1324. THROW( CException( STATUS_TOO_MANY_NODES ) );
  1325. }
  1326. // Clone the previous cursor...
  1327. const CKey & key = *pCursor->GetKey();
  1328. pCursor = QuerySplitCursor( &key );
  1329. xCursor.Set( pCursor );
  1330. // Add it to avoid memory leaks if GetNextKey fails
  1331. curStk.Push(pCursor); // may be wrong pid
  1332. xCursor.Acquire();
  1333. // increment the added cursor
  1334. pKeyCurrent = pCursor->GetNextKey();
  1335. #if CIDBG == 1
  1336. if (pKeyCurrent)
  1337. {
  1338. ciDebugOut(( DEB_ITRACE, " %.*ws, wid %d\n",
  1339. pKeyCurrent->StrLen(), pKeyCurrent->GetStr(), pCursor->WorkId() ));
  1340. }
  1341. else
  1342. ciDebugOut(( DEB_ITRACE, " <NULL> key\n" ));
  1343. #endif
  1344. } while ( pKeyCurrent );
  1345. // Since we have one more cursor in curStk than we wanted...
  1346. curStk.DeleteTop();
  1347. } //CreateRange
  1348. //+---------------------------------------------------------------------------
  1349. //
  1350. // Member: CMasterMergeIndex::Remove, public
  1351. //
  1352. // Synopsis: Closes any open streams/indexes associated with this new
  1353. // master index.
  1354. //
  1355. // History: 30-Mar-94 DwightKr Copied here from CPersIndex
  1356. //
  1357. //----------------------------------------------------------------------------
  1358. void CMasterMergeIndex::Remove()
  1359. {
  1360. Win4Assert( 0 == _pTargetSink );
  1361. Win4Assert( !InUse() );
  1362. Win4Assert( IsZombie() );
  1363. Win4Assert( !_pTargetMasterIndex->InUse() );
  1364. // Win4Assert( !"If you are emptying ci press go.O/W call Srikants/DwightKr" );
  1365. ciFAILTEST( STATUS_NO_MEMORY );
  1366. _pTargetMasterIndex->Remove();
  1367. delete _pTargetMasterIndex;
  1368. _pTargetMasterIndex = 0;
  1369. if ( _pCurrentMasterIndex && !_pCurrentMasterIndex->InUse() )
  1370. {
  1371. _pCurrentMasterIndex->Remove();
  1372. delete _pCurrentMasterIndex;
  1373. _pCurrentMasterIndex = 0;
  1374. }
  1375. }
  1376. //+---------------------------------------------------------------------------
  1377. //
  1378. // Function: AcquireCurrentAndTarget
  1379. //
  1380. // Synopsis: Transfers the ownership of the current and target master
  1381. // indexes to the caller.
  1382. //
  1383. // Arguments: [ppCurrent] -- On output, will have the pointer to the
  1384. // current master (if any). NULL o/w
  1385. // [ppTarget] -- On output, will have the pointer to the
  1386. // target master. Will be non-NULL.
  1387. //
  1388. // History: 9-29-94 srikants Created
  1389. //
  1390. // Notes: This method must be called atmost ONCE during the lifetime
  1391. // of a CMasterMergeIndex. Also, this must be called after
  1392. // this has been zombified and there are no outstanding
  1393. // queries.
  1394. //
  1395. //----------------------------------------------------------------------------
  1396. void CMasterMergeIndex::AcquireCurrentAndTarget(
  1397. CPersIndex ** ppCurrent, CPersIndex ** ppTarget )
  1398. {
  1399. Win4Assert( IsZombie() );
  1400. Win4Assert( !InUse() );
  1401. *ppCurrent = _pCurrentMasterIndex;
  1402. *ppTarget = _pTargetMasterIndex;
  1403. _pCurrentMasterIndex = 0;
  1404. _pTargetMasterIndex = 0;
  1405. }
  1406. //+---------------------------------------------------------------------------
  1407. //
  1408. // Function: RestoreIndexDirectory
  1409. //
  1410. // Synopsis: This method restores the "directory" for the new index
  1411. // in a restarted master merge. It scans the index until
  1412. // it sees the split key and adds it to the directory.
  1413. //
  1414. // Effects:
  1415. //
  1416. // Arguments: [splitKey] - The split key of the new master index.
  1417. // [widMax] - The largest WORKID in the new master index
  1418. // [bitOffStart] - Offset in bits to the end of splitkey
  1419. //
  1420. // History: 4-12-94 srikants Created
  1421. // 5-01-94 DwightKr Split into two functions
  1422. //
  1423. // Notes: Only the index directory needs to be restored when the
  1424. // CMasterMergeIndex object is rebuild during boot time.
  1425. // The keyList directory needs to be rebuild only when
  1426. // actually restarting the master merge.
  1427. //
  1428. // Since it may be quite some time after rebooting a system
  1429. // before the master merge restarts, we don't attempt to rebuild
  1430. // the keylist here.
  1431. //
  1432. //----------------------------------------------------------------------------
  1433. void CMasterMergeIndex::RestoreIndexDirectory(
  1434. const CKeyBuf & idxSplitKey,
  1435. WORKID widMax,
  1436. const BitOffset & idxBitOffRestart )
  1437. {
  1438. Win4Assert( 0 != &GetTargetDir() );
  1439. if ( idxSplitKey.IsMinKey() )
  1440. return;
  1441. // Seek to the idxSplitKey in the new master index. Use the directory
  1442. BitOffset posKey;
  1443. CKeyBuf keyInit;
  1444. const CKey key = idxSplitKey;
  1445. GetTargetDir().Seek( idxSplitKey, & keyInit, posKey );
  1446. CPersDeComp Decomp( GetTargetDir(),
  1447. GetId(),
  1448. _pTargetMasterIndex->GetIndex(),
  1449. posKey,
  1450. keyInit,
  1451. &key,
  1452. widMax,
  1453. TRUE, // Use Links
  1454. FALSE ); // no dir
  1455. BitOffset idxBitOff;
  1456. idxBitOff.Init(0,0);
  1457. CKeyBuf keyLast;
  1458. #if CIDBG == 1
  1459. ciDebugOut(( DEB_ITRACE, "restoring index directory\n" ));
  1460. keyLast.SetPid(pidContents); // arbitrary but not pidAll
  1461. #endif
  1462. for ( const CKeyBuf * pKey = Decomp.GetKey();
  1463. (0 != pKey) ;
  1464. pKey = Decomp.GetNextKey(&idxBitOff) )
  1465. {
  1466. if ( AreEqual(&idxSplitKey, pKey) )
  1467. {
  1468. //
  1469. // Skip over wid-occurences and position to store the next
  1470. // key in the compressor.
  1471. //
  1472. for ( WORKID widSkipped = Decomp.WorkId();
  1473. widInvalid != widSkipped;
  1474. widSkipped = Decomp.NextWorkId() )
  1475. {
  1476. // Null Body
  1477. }
  1478. ciDebugOut(( DEB_ITRACE, "RestoreIndexDirectory - SplitKey Found \n" ));
  1479. break;
  1480. }
  1481. keyLast = *pKey;
  1482. }
  1483. //
  1484. // Make a sanity check to confirm that the compressor and the
  1485. // decompressor arrived at the same offset for the next key.
  1486. // It is extremely important that these match - o/w, the resulting
  1487. // index will be in a corrupt and unusable state.
  1488. //
  1489. BitOffset bitOffCurr;
  1490. Decomp.GetOffset( bitOffCurr );
  1491. ciFAILTEST( CI_CORRUPT_DATABASE );
  1492. if ( !idxSplitKey.IsMaxKey() &&
  1493. ( (bitOffCurr.Page() != idxBitOffRestart.Page()) ||
  1494. (bitOffCurr.Offset() != idxBitOffRestart.Offset()) ) )
  1495. {
  1496. ciDebugOut(( DEB_ERROR,
  1497. "Mismatch in computed vs. stored restart offsets\n" ));
  1498. ciDebugOut(( DEB_ERROR,
  1499. "Computed Page:0x%x Offset:0x%x\n",
  1500. bitOffCurr.Page(), bitOffCurr.Offset() ));
  1501. ciDebugOut(( DEB_ERROR,
  1502. "Saved Page:0x%x Offset:0x%x\n",
  1503. idxBitOffRestart.Page(), idxBitOffRestart.Offset() ));
  1504. Win4Assert( !"Corrupt master merge index" );
  1505. _storage.ReportCorruptComponent( L"MasterMergeIndex2" );
  1506. THROW( CException( CI_CORRUPT_DATABASE ) );
  1507. }
  1508. ciDebugOut(( DEB_ITRACE, "Restart split key is '%ws'\n",
  1509. idxSplitKey.GetStr() ));
  1510. ciDebugOut(( DEB_ITRACE, "Restart page:offset = 0x%x:0x%x\n",
  1511. idxBitOffRestart.Page(), idxBitOffRestart.Offset() ));
  1512. ciDebugOut(( DEB_ITRACE, "restored index directory\n" ));
  1513. } //RestoreIndexDirectory
  1514. #ifdef KEYLIST_ENABLED
  1515. //+---------------------------------------------------------------------------
  1516. //
  1517. // Function: RestoreKeyListDirectory
  1518. //
  1519. // Synopsis: This method restores the "directory" for the new keylist
  1520. // in a restarted master merge. It scans the index until
  1521. // it sees the split key and adds it to the directory.
  1522. //
  1523. // Effects:
  1524. //
  1525. // Arguments: [splitKey] - The split key of the new master index.
  1526. // [widMax] - The largest WORKID in the new master index
  1527. // [bitOffStart] - Offset in bits to the end of splitkey
  1528. //
  1529. // History: 4-12-94 srikants Created
  1530. // 5-01-94 DwightKr Moved into this function
  1531. //
  1532. // Notes: It is assumed that the index directory has already been
  1533. // rebuild when the CMasterMergeIndex object was created. At
  1534. // this point we are restarting a master merge, and the keyList
  1535. // directory is now required.
  1536. //
  1537. //----------------------------------------------------------------------------
  1538. void CMasterMergeIndex::RestoreKeyListDirectory( const CKeyBuf & idxSplitKey,
  1539. WORKID widMax,
  1540. CWKeyList * pKeyList,
  1541. const CKeyBuf & keylstSplitKey
  1542. )
  1543. {
  1544. Win4Assert( &GetTargetDir() );
  1545. Win4Assert( _pTargetSink );
  1546. if ( idxSplitKey.IsMinKey() )
  1547. return;
  1548. Win4Assert( keylstSplitKey.Compare( idxSplitKey ) <= 0 );
  1549. //
  1550. // Seek to the keylstSplitKey in the new master index, and add all
  1551. // subsequent keys found in the new master index to the new keylist
  1552. // index. These keys are missing from the keylist and need to be
  1553. // restored.
  1554. //
  1555. ciFAILTEST( STATUS_NO_MEMORY );
  1556. if ( !GetTargetDir().IsValid() )
  1557. {
  1558. GetTargetDir().LokBuildDir( idxSplitKey );
  1559. }
  1560. BitOffset posKey;
  1561. const CKey splitKeylst = keylstSplitKey;
  1562. // STACKSTACK
  1563. XPtr<CKeyBuf> xKeyInit(new CKeyBuf());
  1564. GetTargetDir().Seek( keylstSplitKey, xKeyInit.GetPointer(), posKey );
  1565. ciFAILTEST( CI_CORRUPT_DATABASE );
  1566. // STACKSTACK
  1567. XPtr<CPersDeComp> xDecomp(
  1568. new CPersDeComp( GetTargetDir(), GetId(),
  1569. _pTargetMasterIndex->GetIndex(), posKey,
  1570. xKeyInit.GetReference(), &splitKeylst, widMax,
  1571. TRUE, // Use Links
  1572. TRUE // Use the directory.
  1573. ) );
  1574. const CKeyBuf * pKey;
  1575. ULONG page = ULONG(-1);
  1576. BitOffset idxBitOff;
  1577. idxBitOff.Init(0,0);
  1578. BitOffset keylstBitOff;
  1579. #if CIDBG == 1
  1580. // STACKSTACK
  1581. XPtr<CKeyBuf> xKeyLast(new CKeyBuf()); // initialized to min key
  1582. xKeyLast->SetPid(pidContents); // arbitrary but not pidAll
  1583. #endif
  1584. for ( pKey = xDecomp->GetKey();
  1585. (0 != pKey) ;
  1586. pKey = xDecomp->GetNextKey(&idxBitOff) )
  1587. {
  1588. if ( pKeyList && (keylstSplitKey.CompareStr( *pKey ) < 0) )
  1589. {
  1590. //
  1591. // pKey is not present in the key list. It must be
  1592. // added.
  1593. //
  1594. pKeyList->PutKey( pKey, keylstBitOff );
  1595. }
  1596. if ( AreEqual(&idxSplitKey, pKey) )
  1597. {
  1598. //
  1599. // Skip over wid-occurences and position to store the next
  1600. // key in the compressor.
  1601. //
  1602. for ( WORKID widSkipped = xDecomp->WorkId();
  1603. widInvalid != widSkipped;
  1604. widSkipped = xDecomp->NextWorkId() )
  1605. {
  1606. // nothing to do.
  1607. }
  1608. ciDebugOut(( DEB_ITRACE, "RestoreKeyListDirectory - SplitKey Found \n" ));
  1609. break;
  1610. }
  1611. #if CIDBG == 1
  1612. xKeyLast.GetReference() = *pKey;
  1613. #endif
  1614. }
  1615. }
  1616. //+---------------------------------------------------------------------------
  1617. //
  1618. // Member: CPersIndex::AcquireRelevantWords, public
  1619. //
  1620. // Synopsis: Return relevant word key ids computed at the most recent
  1621. // master merge. The caller must delete the object returned.
  1622. //
  1623. // Returns: CRWStore *
  1624. //
  1625. // History: 25-Apr-94 v-dlee Created
  1626. //
  1627. //----------------------------------------------------------------------------
  1628. CRWStore * CMasterMergeIndex::AcquireRelevantWords()
  1629. {
  1630. CRWStore *p = _pRWStore;
  1631. ciDebugOut (( DEB_ITRACE,"CPersIndex::acquire _pRWStore: %lx\n",_pRWStore));
  1632. _pRWStore = 0;
  1633. return p;
  1634. } //AcquireRelevantWords
  1635. //+---------------------------------------------------------------------------
  1636. //
  1637. // Member: CPersIndex::ComputeRelevantWords, public
  1638. //
  1639. // Synopsis: Compute and return relevant word key ids
  1640. //
  1641. // Arguments: [cRows] -- # of wids in pwid array
  1642. // [cRW] -- max # of rw keys per wid
  1643. // [pwid] -- an array of wids in increasing order whose
  1644. // rw key ids are to be returned
  1645. // [pKeyList] -- keylist to use in translation of keys to ids
  1646. //
  1647. // Returns: CRWStore *
  1648. //
  1649. // History: 25-Apr-94 v-dlee Created
  1650. //
  1651. //----------------------------------------------------------------------------
  1652. CRWStore * CMasterMergeIndex::ComputeRelevantWords(ULONG cRows,ULONG cRW,
  1653. WORKID *pwid,CKeyList *pKeyList)
  1654. {
  1655. Win4Assert( !" Not Yet Implemented" );
  1656. #ifdef RELEVANT_WORDS_ENABLED
  1657. ciDebugOut((DEB_ITRACE,"ComputeRelevantWords top\n"));
  1658. //
  1659. // Get the resources needed to do the computation
  1660. //
  1661. CRelevantWord RelWord(pwid,cRows,cRW);
  1662. CPersIndexCursor indCur(this);
  1663. CKeyListCursor keylCur(pKeyList);
  1664. //
  1665. // Walk through the index and find occurances of keys in the wids
  1666. //
  1667. const CKeyBuf * pKey, * pklKey;
  1668. for (pKey = indCur->GetKey(), pklKey = keylCur->GetKey();
  1669. pKey != 0; pKey = indCur->GetNextKey())
  1670. {
  1671. if (pKey->Pid() == pidContents &&
  1672. ((CKeyBuf * const) pKey)->IsPossibleRW())
  1673. {
  1674. ULONG cWids = 0;
  1675. for (WORKID wid = indCur->WorkId(); wid != widInvalid;
  1676. wid = indCur->NextWorkId())
  1677. {
  1678. cWids++;
  1679. if (RelWord.isTrackedWid(wid))
  1680. RelWord.Add(wid,indCur->OccurrenceCount());
  1681. }
  1682. //
  1683. // Walk the keylist until we match it up with where the
  1684. // index cursor is.
  1685. //
  1686. while (pklKey->CompareStr(*pKey) != 0)
  1687. pklKey = keylCur->GetNextKey();
  1688. RelWord.DoneWithKey(pklKey->Pid(),MaxWorkId(),cWids);
  1689. }
  1690. }
  1691. return RelWord.AcquireStore();
  1692. #endif // RELEVANT_WORDS_ENABLED
  1693. return(0);
  1694. } //ComputeRelevantWords
  1695. #endif // KEYLIST_ENABLED
  1696. //+---------------------------------------------------------------------------
  1697. //
  1698. // Function: CTrackSplitKey::CTrackSplitKey
  1699. //
  1700. // Synopsis: The split key tracking constructor. Initializes the object
  1701. // to have "min" keys and offsets are all set to the beginning
  1702. // of the stream.
  1703. //
  1704. // Arguments: [splitKey] -- splitkey being tracked
  1705. // [bitoffBeginSplit] -- bit offset to beginning of split ket
  1706. // [bitoffEndSplit] -- bit offset to end of splitkey
  1707. //
  1708. // History: 4-12-94 srikants Created
  1709. //
  1710. // Notes:
  1711. //
  1712. //----------------------------------------------------------------------------
  1713. CTrackSplitKey::CTrackSplitKey( const CKeyBuf & splitKey,
  1714. const BitOffset & bitoffBeginSplit,
  1715. const BitOffset & bitoffEndSplit ) :
  1716. _fNewSplitKeyFound(FALSE)
  1717. {
  1718. _splitKey2.SetKey( splitKey );
  1719. _splitKey2.SetBeginOffset( bitoffBeginSplit );
  1720. _splitKey2.SetEndOffset( bitoffEndSplit );
  1721. }
  1722. //+---------------------------------------------------------------------------
  1723. //
  1724. // Function: BeginNewKey
  1725. //
  1726. // Synopsis: This method informs the split key tracker that a new key
  1727. // has been added to the compressor. It will check if the
  1728. // previous key and the current key are landing on a different
  1729. // page and check if a split key has been found.
  1730. //
  1731. // Arguments: [newKey] -- The new key added to the compressor
  1732. // [beginNewOff] -- Starting offset of the new key. This will
  1733. // be the end offset of the current key.
  1734. //
  1735. // History: 4-19-94 srikants Created
  1736. //
  1737. // Notes:
  1738. //
  1739. //----------------------------------------------------------------------------
  1740. void CTrackSplitKey::BeginNewKey( const CKeyBuf & newKey,
  1741. const BitOffset & beginNewOff,
  1742. WORKID widMax )
  1743. {
  1744. //
  1745. // beginNewOff is also the end of current key. We have to determine
  1746. // if there is a new split key.
  1747. //
  1748. _currKey.SetEndOffset( beginNewOff );
  1749. if ( CiPageToCommonPage(_currKey.GetEndOffset().Page()) >
  1750. CiPageToCommonPage(_prevKey.GetEndOffset().Page()) )
  1751. {
  1752. //
  1753. // We have a candidate split key in the previous key.
  1754. //
  1755. _splitKey2 = _splitKey1;
  1756. _splitKey1 = _prevKey;
  1757. _fNewSplitKeyFound = !_splitKey2.GetKey().IsMinKey();
  1758. #if CIDBG == 1
  1759. if ( IsNewKeyFound() )
  1760. {
  1761. ciDebugOut(( DEB_PCOMP,
  1762. "Split Key Found At Page 0x%X Offset 0x%X\n",
  1763. _splitKey2.GetBeginOffset().Page(),
  1764. _splitKey2.GetBeginOffset().Offset() ));
  1765. ciDebugOut(( DEB_PCOMP,
  1766. "End of Split Key found at page 0x%x offset 0x%x\n",
  1767. _splitKey2.GetEndOffset().Page(),
  1768. _splitKey2.GetEndOffset().Offset() ));
  1769. }
  1770. #endif // CIDBG
  1771. }
  1772. _prevKey = _currKey;
  1773. _currKey.SetKey( newKey );
  1774. _currKey.SetBeginOffset( beginNewOff );
  1775. _currKey.SetWidMax( widMax );
  1776. }
  1777. //+---------------------------------------------------------------------------
  1778. //
  1779. // Function: CSplitKeyInfo
  1780. //
  1781. // Synopsis: Constructor the CSplitKeyInfo
  1782. //
  1783. // Effects: Initializes the key to be minkey and offsets to 0,0.
  1784. //
  1785. // History: 4-19-94 srikants Created
  1786. //
  1787. // Notes:
  1788. //
  1789. //----------------------------------------------------------------------------
  1790. CSplitKeyInfo::CSplitKeyInfo()
  1791. {
  1792. _start.Init(0,0);
  1793. _end.Init(0,0);
  1794. _key.FillMin();
  1795. _widMax = widInvalid;
  1796. }