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.

994 lines
29 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 1998.
  5. //
  6. // File: PINDEX.CXX
  7. //
  8. // Contents: Persistent Index
  9. //
  10. // Classes: CPersIndex, CMergeSourceCursor
  11. //
  12. // History: 03-Apr-91 BartoszM Created stub.
  13. // 20-Apr-94 DwightKr Moved CMergeSourceCursor here
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.cxx>
  17. #pragma hdrstop
  18. #include <pdir.hxx>
  19. #include <pstore.hxx>
  20. #include <pidxtbl.hxx>
  21. #include <rwex.hxx>
  22. #include "pindex.hxx"
  23. #include "pcomp.hxx"
  24. #include "mcursor.hxx"
  25. #include "fresh.hxx"
  26. #include "physidx.hxx"
  27. #include "pcomp.hxx"
  28. #include "fretest.hxx"
  29. #include "indsnap.hxx"
  30. #include "keylist.hxx"
  31. #include "partn.hxx"
  32. unsigned const FOUR_MEGABYTES = 0x400000;
  33. //+---------------------------------------------------------------------------
  34. //
  35. // Member: CPersIndex::Size, public
  36. //
  37. // Synopsis: Returns size in pages
  38. //
  39. // History: 22-May-92 BartoszM Created.
  40. //
  41. //----------------------------------------------------------------------------
  42. unsigned CPersIndex::Size() const
  43. {
  44. return _xPhysIndex->PageSize();
  45. }
  46. void CPersIndex::FillRecord ( CIndexRecord& record )
  47. {
  48. record._objectId = ObjectId();
  49. record._iid = GetId();
  50. record._type = IsMaster()? itMaster: itShadow;
  51. record._maxWorkId = MaxWorkId();
  52. }
  53. //+---------------------------------------------------------------------------
  54. //
  55. // Member: CPersIndex::CPersIndex, public
  56. //
  57. // Synopsis: Create an empty index
  58. //
  59. // Arguments: [id] -- index id
  60. // [storage] -- physical storage
  61. //
  62. // History: 3-Apr-91 BartoszM Created.
  63. //
  64. //----------------------------------------------------------------------------
  65. CPersIndex::CPersIndex(
  66. PStorage & storage,
  67. WORKID objectId,
  68. INDEXID iid,
  69. unsigned c4KPages,
  70. CDiskIndex::EDiskIndexType idxType ) :
  71. CDiskIndex( iid, idxType ),
  72. _sigPersIndex( eSigPersIndex ),
  73. _storage( storage ),
  74. _obj( storage.QueryObject( objectId ) ),
  75. _fAbortMerge( FALSE )
  76. {
  77. XPtr<PMmStream> sStream( storage.QueryNewIndexStream( _obj.GetObj(),
  78. CDiskIndex::eMaster == idxType ) );;
  79. _xPhysIndex.Set( new CPhysIndex( storage,
  80. _obj.GetObj(),
  81. objectId,
  82. c4KPages,
  83. sStream ) );
  84. _xPhysIndex->SetPageGrowth( FOUR_MEGABYTES / CI_PAGE_SIZE );
  85. Win4Assert( 0 == sStream.GetPointer() );
  86. _xDir.Set( _storage.QueryNewDirectory( _obj.GetObj() ) );
  87. }
  88. //+---------------------------------------------------------------------------
  89. //
  90. // Member: CPersIndex::CPersIndex, public
  91. //
  92. // Synopsis: Restore an index from storage
  93. //
  94. // Arguments: [id] -- index id
  95. // [storage] -- physical storage
  96. // [widMax] -- max work id
  97. // [isMaster] -- Set to TRUE if this is a master index.
  98. // [fWritable] -- Set to TRUE if various streams should be
  99. // opened for Write access.
  100. // [fReadDir] -- should the directory be opened for r or r/w
  101. //
  102. // History: 3-Apr-91 BartoszM Created.
  103. //
  104. //----------------------------------------------------------------------------
  105. CPersIndex::CPersIndex(
  106. PStorage & storage,
  107. WORKID objectId,
  108. INDEXID iid,
  109. WORKID widMax,
  110. CDiskIndex::EDiskIndexType idxType,
  111. PStorage::EOpenMode mode,
  112. BOOL fReadDir ) :
  113. CDiskIndex( iid, idxType, widMax ),
  114. _sigPersIndex( eSigPersIndex ),
  115. _storage( storage ),
  116. _obj( storage.QueryObject( objectId ) ),
  117. _fAbortMerge( FALSE )
  118. {
  119. Win4Assert( PStorage::eOpenForWrite == mode ||
  120. PStorage::eOpenForRead == mode );
  121. PStorage::EOpenMode modeIndex = mode;
  122. //
  123. // Open master indexes writable so we can shrink them from the front
  124. //
  125. if ( CDiskIndex::eMaster == idxType )
  126. modeIndex = PStorage::eOpenForWrite;
  127. PMmStream * pStream = storage.QueryExistingIndexStream( _obj.GetObj(),
  128. modeIndex );
  129. XPtr<PMmStream> sStream( pStream );
  130. _xPhysIndex.Set( new CPhysIndex( storage,
  131. _obj.GetObj(),
  132. objectId,
  133. modeIndex,
  134. sStream ) );
  135. Win4Assert( 0 == sStream.GetPointer() );
  136. Win4Assert( fReadDir );
  137. if ( fReadDir )
  138. _xDir.Set( _storage.QueryExistingDirectory( _obj.GetObj(), mode ) );
  139. else
  140. _xDir.Set( _storage.QueryNewDirectory( _obj.GetObj() ) );
  141. }
  142. //+---------------------------------------------------------------------------
  143. //
  144. // Member: CMergeSourceCursor::CMergeSourceCursor
  145. //
  146. // Synopsis: Constructor
  147. //
  148. // History: 29-Aug-92 BartoszM Created
  149. //
  150. //----------------------------------------------------------------------------
  151. CMergeSourceCursor::CMergeSourceCursor ( CIndexSnapshot& indSnap,
  152. const CKeyBuf * pKey )
  153. {
  154. if (0 != pKey)
  155. {
  156. CKey SplitKey(*pKey);
  157. _pCurSrc = indSnap.QueryMergeCursor ( &SplitKey );
  158. }
  159. else
  160. {
  161. _pCurSrc = indSnap.QueryMergeCursor ();
  162. }
  163. }
  164. //+---------------------------------------------------------------------------
  165. //
  166. // Member: CMergeSourceCursor::~CMergeSourceCursor
  167. //
  168. // Synopsis: Destructor
  169. //
  170. // History: 29-Aug-92 BartoszM Created
  171. //
  172. //----------------------------------------------------------------------------
  173. CMergeSourceCursor::~CMergeSourceCursor ()
  174. {
  175. delete _pCurSrc;
  176. }
  177. //+---------------------------------------------------------------------------
  178. //
  179. // Member: CPersIndex::Merge, public
  180. //
  181. // Synopsis: Merge index(es) into an empty pesistent index.
  182. //
  183. // Effects: Fills the persistent index with data from the input
  184. // indexes.
  185. // [fresh] is deleted.
  186. //
  187. // Arguments: [indSnap] -- array of indexes to be merged
  188. // [pNewKeyList] -- Keylist to merge (master merge only)
  189. // [mergeProgress] -- % merge complete
  190. //
  191. // Requires: The index is initially empty.
  192. //
  193. // Notes: Every compressor is transacted.
  194. //
  195. // History: 15-May-91 KyleP Use new PutOccurrence() method.
  196. // 16-Apr-91 KyleP Created.
  197. // 17-Feb-93 KyleP Merge keylist
  198. // 25-Oct-95 DwightKr Add merge complete measurement
  199. //
  200. //----------------------------------------------------------------------------
  201. void CPersIndex::Merge( CIndexSnapshot& indSnap,
  202. const CPartition & partn,
  203. CCiFrmPerfCounter & mergeProgress,
  204. BOOL fGetRW )
  205. {
  206. // Calculate max of all input widMaxs
  207. #if CIDBG == 1
  208. unsigned cKey = 0;
  209. #endif
  210. WORKID widMax = indSnap.MaxWorkId();
  211. ciDebugOut (( DEB_ITRACE, "Max work id %ld\n", widMax ));
  212. SetMaxWorkId ( widMax );
  213. CFreshTest* pFreshTest = indSnap.GetFresh();
  214. CKeyBuf keyLast;
  215. CMergeSourceCursor pCurSrc( indSnap );
  216. if ( !pCurSrc.IsEmpty() )
  217. {
  218. //
  219. // Read-ahead on the source indexes results in better merge
  220. // performance, but slower queries. Temporarily switch modes.
  221. //
  222. CSetReadAhead readAhead( _storage );
  223. CPersComp compr( _xPhysIndex.GetReference(), _widMax );
  224. ciDebugOut (( DEB_ITRACE, "widMax passed to compressor: %ld\n",
  225. _widMax ));
  226. const CKeyBuf * pKey;
  227. ULONG page = ULONG(-1);
  228. BitOffset bitOff;
  229. #if CIDBG == 1
  230. keyLast.SetPid(pidContents); // arbitrary but not pidAll
  231. #endif
  232. #if CIDBG == 1
  233. WCHAR FirstLetter = '@';
  234. #endif
  235. mergeProgress.Update( 0 );
  236. ciDebugOut (( DEB_ITRACE,"Merging. Merge on letter: "));
  237. for (pKey = pCurSrc->GetKey();
  238. pKey != NULL; pKey = pCurSrc->GetNextKey())
  239. {
  240. #if CIDBG == 1
  241. cKey++;
  242. if ( *(pKey->GetStr()) != FirstLetter )
  243. {
  244. FirstLetter = *(pKey->GetStr());
  245. if ( FirstLetter < L'~' )
  246. ciDebugOut(( DEB_NOCOMPNAME | DEB_ITRACE | DEB_PENDING, "%c",
  247. FirstLetter ));
  248. else
  249. ciDebugOut(( DEB_NOCOMPNAME | DEB_ITRACE | DEB_PENDING, "<%04x>",
  250. FirstLetter ));
  251. }
  252. #endif
  253. //
  254. // Don't store empty keys
  255. //
  256. WORKID wid = pCurSrc->WorkId();
  257. if ( wid == widInvalid )
  258. continue;
  259. //
  260. // Add the key to the new index.
  261. //
  262. // This would later lead to a divide by 0
  263. Win4Assert( 0 != pCurSrc->WorkIdCount() );
  264. compr.PutKey(pKey, pCurSrc->WorkIdCount(), bitOff);
  265. for ( ;
  266. wid != widInvalid;
  267. wid = pCurSrc->NextWorkId())
  268. {
  269. // fresh test
  270. CFreshTest::IndexSource indexSrc =
  271. pFreshTest->IsCorrectIndex (pCurSrc->IndexId(), wid);
  272. //
  273. // There should always be an entry for a workid in the fresh
  274. // test whose data is contained in a wordlist/shadow-index.
  275. //
  276. Win4Assert( CFreshTest::Master != indexSrc );
  277. if ( CFreshTest::Invalid != indexSrc )
  278. {
  279. compr.PutWorkId(wid, pCurSrc->MaxOccurrence(), pCurSrc->OccurrenceCount());
  280. for (OCCURRENCE occ = pCurSrc->Occurrence();
  281. occ != OCC_INVALID;
  282. occ = pCurSrc->NextOccurrence())
  283. {
  284. compr.PutOccurrence(occ);
  285. }
  286. }
  287. }
  288. //
  289. // If this key didn't have any wids then we can delete it from
  290. // the new index. Otherwise, track it as a possible splitkey
  291. // and update the index as necessary.
  292. //
  293. if ( bitOff.Page() != page )
  294. {
  295. page = bitOff.Page();
  296. _xDir->Add ( bitOff, *pKey );
  297. }
  298. else
  299. {
  300. Win4Assert( page == _xDir->GetBitOffsetLastAdded().Page() );
  301. }
  302. keyLast = *pKey;
  303. //
  304. // There's no point in special abort code. We have to handle
  305. // exceptions anyway.
  306. //
  307. if ( _fAbortMerge || partn.IsCleaningUp() )
  308. {
  309. ciDebugOut(( DEB_ITRACE, "Aborting Merge\n" ));
  310. THROW( CException( STATUS_UNSUCCESSFUL ) );
  311. }
  312. mergeProgress.Update( _xPhysIndex->PagesInUse() * 100 / _xPhysIndex->PageSize() );
  313. }
  314. ciDebugOut(( DEB_ITRACE | DEB_PENDING, "%d keys in index\n", cKey ));
  315. // add sentinel key
  316. keyLast.FillMax();
  317. keyLast.SetPid( pidContents );
  318. compr.PutKey( &keyLast, 1, bitOff );
  319. //
  320. // If the MaxKey is the first key on a page, it must be added
  321. // to the directory.
  322. //
  323. if ( bitOff.Page() != page )
  324. {
  325. page = bitOff.Page();
  326. _xDir->Add ( bitOff, keyLast );
  327. }
  328. else
  329. {
  330. Win4Assert( page == _xDir->GetBitOffsetLastAdded().Page() );
  331. }
  332. mergeProgress.Update( 100 );
  333. compr.FreeStream();
  334. } // compr goes out of scope
  335. else
  336. {
  337. ciDebugOut (( DEB_ITRACE, "No merge cursor created\n" ));
  338. CPersComp compr( _xPhysIndex.GetReference(), _widMax );
  339. keyLast.FillMax();
  340. keyLast.SetPid(pidContents);
  341. BitOffset bitOff;
  342. compr.PutKey( &keyLast, 1, bitOff );
  343. compr.FreeStream();
  344. }
  345. //
  346. // Compressor MUST NOT be in scope here.
  347. //
  348. keyLast.FillMax();
  349. _xDir->LokFlushDir( keyLast );
  350. _xDir->LokBuildDir( keyLast );
  351. // after compr is dead
  352. _xPhysIndex->Flush();
  353. _xPhysIndex->Reopen( FALSE );
  354. } //Merge
  355. //+---------------------------------------------------------------------------
  356. //
  357. // Member: CPersIndex::QueryCursor, public
  358. //
  359. // Synopsis: Return a cursor for the whole persistent index.
  360. //
  361. // Returns: A new cursor.
  362. //
  363. // History: 24-Apr-91 KyleP Created.
  364. //
  365. //----------------------------------------------------------------------------
  366. CKeyCursor * CPersIndex::QueryCursor()
  367. {
  368. CKey key;
  369. key.FillMin();
  370. return QueryKeyCursor( &key );
  371. }
  372. //+---------------------------------------------------------------------------
  373. //
  374. // Member: CPersIndex::QueryKeyCursor, public
  375. //
  376. // Synopsis: Return a key cursor for the shadow index when restarting a
  377. // master merge
  378. //
  379. // Returns: A new cursor.
  380. //
  381. // History: 12-Apr-94 DwightKr Created.
  382. //
  383. //----------------------------------------------------------------------------
  384. CKeyCursor * CPersIndex::QueryKeyCursor(const CKey * pKey)
  385. {
  386. BitOffset posKey;
  387. CKeyBuf keyInit;
  388. _xDir->Seek( *pKey, &keyInit, posKey );
  389. ciDebugOut(( DEB_ITRACE, "found key %.*ws at %lx:%lx\n",
  390. keyInit.StrLen(), keyInit.GetStr(),
  391. posKey.Page(), posKey.Offset() ));
  392. XPtr<CPersDeComp> xCursor( new CPersDeComp( _xDir.GetReference(),
  393. GetId(),
  394. _xPhysIndex.GetReference(),
  395. posKey,
  396. keyInit,
  397. pKey,
  398. _widMax ) );
  399. if ( 0 == xCursor->GetKey() )
  400. xCursor.Free();
  401. return xCursor.Acquire();
  402. } //QueryKeyCursor
  403. //+---------------------------------------------------------------------------
  404. //
  405. // Member: CPersIndex::QueryCursor, public
  406. //
  407. // Synopsis: Return a cursor for the persistent index.
  408. //
  409. // Arguments: [pKey] -- Key to initially seek for.
  410. // [isRange] -- TRUE for range query
  411. // [cMaxNodes] -- Max number of nodes to create. Decremented
  412. // on return.
  413. //
  414. // Returns: A new cursor.
  415. //
  416. // History: 24-Apr-91 KyleP Created.
  417. //
  418. //----------------------------------------------------------------------------
  419. COccCursor * CPersIndex::QueryCursor( const CKey * pKey,
  420. BOOL isRange,
  421. ULONG & cMaxNodes )
  422. {
  423. Win4Assert( cMaxNodes > 0 );
  424. if (isRange)
  425. {
  426. CKey keyEnd;
  427. keyEnd.FillMax (*pKey);
  428. return QueryRangeCursor (pKey, &keyEnd, cMaxNodes);
  429. }
  430. if (pKey->Pid() == pidAll)
  431. return QueryRangeCursor ( pKey, pKey, cMaxNodes );
  432. cMaxNodes--;
  433. if ( 0 == cMaxNodes )
  434. {
  435. ciDebugOut(( DEB_WARN, "Node limit reached in CPersIndex::QueryCursor.\n" ));
  436. THROW( CException( STATUS_TOO_MANY_NODES ) );
  437. }
  438. BitOffset posKey;
  439. CKeyBuf keyInit;
  440. _xDir->Seek( *pKey, &keyInit, posKey );
  441. ciDebugOut(( DEB_ITRACE, "found key %.*ws at %lx:%lx\n",
  442. keyInit.StrLen(), keyInit.GetStr(),
  443. posKey.Page(), posKey.Offset() ));
  444. XPtr<CPersDeComp> xCursor( new CPersDeComp( _xDir.GetReference(),
  445. GetId(),
  446. _xPhysIndex.GetReference(),
  447. posKey,
  448. keyInit,
  449. pKey,
  450. _widMax ) );
  451. if ( xCursor->GetKey() == 0 || !pKey->MatchPid( *xCursor->GetKey())
  452. || pKey->CompareStr(*xCursor->GetKey()) != 0 )
  453. {
  454. xCursor.Free();
  455. }
  456. return xCursor.Acquire();
  457. } //QueryCursor
  458. //+---------------------------------------------------------------------------
  459. //
  460. // Member: CPersIndex::QueryRangeCursor, public
  461. //
  462. // Synopsis: Return a range cursor for the persistent index.
  463. //
  464. // Arguments: [pKey] -- Key at beginning of the range.
  465. // [pKeyEnd] -- Key at the end of the range.
  466. // [cMaxNodes] -- Max number of nodes to create. Decremented
  467. // on return.
  468. //
  469. // Returns: A new cursor.
  470. //
  471. // History: 11-Dec-91 AmyA Created.
  472. // 31-Jan-92 AmyA Moved code to CreateRange().
  473. //
  474. //----------------------------------------------------------------------------
  475. COccCursor * CPersIndex::QueryRangeCursor( const CKey * pKey,
  476. const CKey * pKeyEnd,
  477. ULONG & cMaxNodes )
  478. {
  479. Win4Assert( cMaxNodes > 0 );
  480. COccCurStack curStk;
  481. CreateRange(curStk, pKey, pKeyEnd, cMaxNodes );
  482. return curStk.QuerySynCursor( MaxWorkId() );
  483. }
  484. //+---------------------------------------------------------------------------
  485. //
  486. // Member: CPersIndex::QuerySynCursor, public
  487. //
  488. // Synopsis: Return a synonym cursor for the persistent index.
  489. //
  490. // Arguments: [keyStk] -- Stack of keys to be searched for.
  491. // [isRange] -- Whether or not this is a range search.
  492. // [cMaxNodes] -- Max number of nodes to create. Decremented
  493. // on return.
  494. //
  495. // Returns: A new cursor.
  496. //
  497. // History: 31-Jan-92 AmyA Created.
  498. //
  499. //----------------------------------------------------------------------------
  500. COccCursor * CPersIndex::QuerySynCursor( CKeyArray & keyArr,
  501. BOOL isRange,
  502. ULONG & cMaxNodes )
  503. {
  504. COccCurStack curStk;
  505. int keyCount = keyArr.Count();
  506. for (int i = 0; i < keyCount; i++)
  507. {
  508. Win4Assert( cMaxNodes > 0 );
  509. CKey& key = keyArr.Get(i);
  510. if (isRange)
  511. {
  512. CKey keyEnd;
  513. keyEnd.FillMax(key);
  514. CreateRange(curStk, &key, &keyEnd, cMaxNodes );
  515. }
  516. else if ( key.Pid() == pidAll )
  517. {
  518. CreateRange ( curStk, &key, &key, cMaxNodes );
  519. }
  520. else
  521. {
  522. XPtr<COccCursor> xCursor( QueryCursor( &key, FALSE, cMaxNodes ) );
  523. if ( !xCursor.IsNull() )
  524. {
  525. curStk.Push( xCursor.GetPointer() );
  526. xCursor.Acquire();
  527. }
  528. }
  529. }
  530. return(curStk.QuerySynCursor( MaxWorkId()));
  531. }
  532. //+---------------------------------------------------------------------------
  533. //
  534. // Member: CPersIndex::CreateRange, private
  535. //
  536. // Synopsis: Adds all cursors with keys between pKey and pKeyEnd to curStk.
  537. //
  538. // Arguments: [curStk] -- CKeyCurStack to add cursors to.
  539. // [pKey] -- Key at beginning of range.
  540. // [pKeyEnd] -- End of key range.
  541. // [cMaxNodes] -- Max number of nodes to create. Decremented
  542. // on return.
  543. //
  544. // History: 31-Jan-92 AmyA Created.
  545. //
  546. //----------------------------------------------------------------------------
  547. void CPersIndex::CreateRange( COccCurStack & curStk,
  548. const CKey * pKeyStart,
  549. const CKey * pKeyEnd,
  550. ULONG & cMaxNodes )
  551. {
  552. Win4Assert( cMaxNodes > 0 );
  553. cMaxNodes--;
  554. if ( 0 == cMaxNodes )
  555. {
  556. ciDebugOut(( DEB_WARN, "Node limit reached in CPersIndex::CreateRange.\n" ));
  557. THROW( CException( STATUS_TOO_MANY_NODES ) );
  558. }
  559. BitOffset posKey;
  560. CKeyBuf keyInit;
  561. _xDir->Seek( *pKeyStart, &keyInit, posKey );
  562. ciDebugOut (( DEB_ITRACE, "CreateRange %.*ws-%.*ws. Dir seek %.*ws, pid %d\n",
  563. pKeyStart->StrLen(), pKeyStart->GetStr(),
  564. pKeyEnd->StrLen(), pKeyEnd->GetStr(),
  565. keyInit.StrLen(), keyInit.GetStr(),
  566. keyInit.Pid() ));
  567. CPersDeComp* pCursor = new CPersDeComp( _xDir.GetReference(),
  568. GetId(),
  569. _xPhysIndex.GetReference(),
  570. posKey,
  571. keyInit,
  572. pKeyStart,
  573. _widMax);
  574. XPtr<CPersDeComp> xCursor( pCursor );
  575. const CKeyBuf * pKeyCurrent = pCursor->GetKey();
  576. if ( 0 == pKeyCurrent )
  577. return;
  578. PROPID pid = pKeyStart->Pid();
  579. curStk.Push(pCursor);
  580. xCursor.Acquire();
  581. ciDebugOut(( DEB_ITRACE, "First key %.*ws, pid %d\n",
  582. pKeyCurrent->StrLen(), pKeyCurrent->GetStr(), pKeyCurrent->Pid() ));
  583. do
  584. {
  585. if (pid != pidAll) // exact pid match
  586. {
  587. // skip wrong pids
  588. while (pid != pKeyCurrent->Pid())
  589. {
  590. #if CIDBG == 1 //------------------------------------------
  591. if (pKeyCurrent)
  592. {
  593. ciDebugOut(( DEB_ITRACE, " skip: %.*ws, pid %d, wid %d\n",
  594. pKeyCurrent->StrLen(),
  595. pKeyCurrent->GetStr(),
  596. pKeyCurrent->Pid(),
  597. pCursor->WorkId() ));
  598. }
  599. else
  600. ciDebugOut(( DEB_ITRACE, " <NULL> key\n" ));
  601. #endif //--------------------------------------------------
  602. pKeyCurrent = pCursor->GetNextKey();
  603. if (pKeyCurrent == 0
  604. || pKeyEnd->CompareStr(*pKeyCurrent) < 0 )
  605. break;
  606. }
  607. // either pid matches or we have overshot
  608. // i.e. different pids and current string > end
  609. }
  610. if (pKeyCurrent == 0 || !pKeyEnd->MatchPid (*pKeyCurrent)
  611. || pKeyEnd->CompareStr (*pKeyCurrent) < 0 )
  612. {
  613. break; // <--- LOOP EXIT
  614. }
  615. cMaxNodes--;
  616. if ( 0 == cMaxNodes )
  617. {
  618. ciDebugOut(( DEB_WARN, "Node limit reached in CPersIndex::CreateRange.\n" ));
  619. THROW( CException( STATUS_TOO_MANY_NODES ) );
  620. }
  621. // Clone the previous cursor...
  622. pCursor = new CPersDeComp(*pCursor);
  623. xCursor.Set( pCursor );
  624. // Add it to avoid memory leaks if GetNextKey fails
  625. curStk.Push(pCursor); // may be wrong pid
  626. xCursor.Acquire();
  627. // increment the added cursor
  628. pKeyCurrent = pCursor->GetNextKey();
  629. #if CIDBG == 1
  630. if (pKeyCurrent)
  631. {
  632. ciDebugOut(( DEB_ITRACE, " %.*ws, wid %d\n",
  633. pKeyCurrent->StrLen(), pKeyCurrent->GetStr(), pCursor->WorkId() ));
  634. }
  635. else
  636. ciDebugOut(( DEB_ITRACE, " <NULL> key\n" ));
  637. #endif
  638. } while ( pKeyCurrent );
  639. // Since we have one more cursor in curStk than we wanted...
  640. curStk.DeleteTop();
  641. }
  642. //+---------------------------------------------------------------------------
  643. //
  644. // Member: CPersIndex::Remove, public
  645. //
  646. // Synopsis: Remove index from storage
  647. //
  648. // History: 02-May-91 BartoszM Created.
  649. //
  650. //----------------------------------------------------------------------------
  651. void CPersIndex::Remove()
  652. {
  653. _xPhysIndex->Close();
  654. _xDir->Close();
  655. _obj->Close();
  656. if ( !_storage.RemoveObject( ObjectId() ) )
  657. {
  658. DWORD dwError = GetLastError();
  659. ciDebugOut(( DEB_ERROR, "Delete of index %08x failed: %d\n",
  660. ObjectId(), dwError ));
  661. }
  662. }
  663. #ifdef KEYLIST_ENABLED
  664. //+---------------------------------------------------------------------------
  665. //
  666. // Member: CPersIndex::AcquireRelevantWords, public
  667. //
  668. // Synopsis: Return relevant word key ids computed at the most recent
  669. // master merge. The caller must delete the object returned.
  670. //
  671. // Returns: CRWStore *
  672. //
  673. // History: 25-Apr-94 v-dlee Created
  674. //
  675. //----------------------------------------------------------------------------
  676. CRWStore * CPersIndex::AcquireRelevantWords()
  677. {
  678. CRWStore *p = _pRWStore;
  679. ciDebugOut (( DEB_ITRACE,"CPersIndex::acquire _pRWStore: %lx\n",_pRWStore));
  680. _pRWStore = 0;
  681. return p;
  682. } //AcquireRelevantWords
  683. //+---------------------------------------------------------------------------
  684. //
  685. // Member: CPersIndex::ComputeRelevantWords, public
  686. //
  687. // Synopsis: Compute and return relevant word key ids
  688. //
  689. // Arguments: [cRows] -- # of wids in pwid array
  690. // [cRW] -- max # of rw keys per wid
  691. // [pwid] -- an array of wids in increasing order whose
  692. // rw key ids are to be returned
  693. // [pKeyList] -- keylist to use in translation of keys to ids
  694. //
  695. // Returns: CRWStore *
  696. //
  697. // History: 25-Apr-94 v-dlee Created
  698. //
  699. //----------------------------------------------------------------------------
  700. CRWStore * CPersIndex::ComputeRelevantWords(ULONG cRows,ULONG cRW,
  701. WORKID *pwid,CKeyList *pKeyList)
  702. {
  703. ciDebugOut((DEB_ITRACE,"ComputeRelevantWords top\n"));
  704. //
  705. // Get the resources needed to do the computation
  706. //
  707. CRelevantWord RelWord(pwid,cRows,cRW);
  708. CPersIndexCursor indCur(this);
  709. CKeyListCursor keylCur(pKeyList);
  710. //
  711. // Walk through the index and find occurances of keys in the wids
  712. //
  713. const CKeyBuf * pKey, * pklKey;
  714. for (pKey = indCur->GetKey(), pklKey = keylCur->GetKey();
  715. pKey != 0; pKey = indCur->GetNextKey())
  716. {
  717. if (pKey->Pid() == pidContents &&
  718. ((CKeyBuf * const) pKey)->IsPossibleRW())
  719. {
  720. ULONG cWids = 0;
  721. for (WORKID wid = indCur->WorkId(); wid != widInvalid;
  722. wid = indCur->NextWorkId())
  723. {
  724. cWids++;
  725. if (RelWord.isTrackedWid(wid))
  726. RelWord.Add(wid,indCur->OccurrenceCount());
  727. }
  728. //
  729. // Walk the keylist until we match it up with where the
  730. // index cursor is.
  731. //
  732. while (pklKey->CompareStr(*pKey) != 0)
  733. pklKey = keylCur->GetNextKey();
  734. RelWord.DoneWithKey(pklKey->Pid(),MaxWorkId(),cWids);
  735. }
  736. }
  737. return RelWord.AcquireStore();
  738. } //ComputeRelevantWords
  739. #endif // KEYLIST_ENABLED
  740. //+---------------------------------------------------------------------------
  741. //
  742. // Member: CPersIndex::MakeBackupCopy
  743. //
  744. // Synopsis: Makes a copy of the index and directory using the storage
  745. // provided.
  746. //
  747. // Arguments: [storage] - Storage
  748. //
  749. // History: 3-17-97 srikants Created
  750. //
  751. //----------------------------------------------------------------------------
  752. void CPersIndex::MakeBackupCopy( PStorage & storage,
  753. WORKID wid,
  754. PSaveProgressTracker & tracker )
  755. {
  756. //
  757. // Create an index in the destination storage.
  758. //
  759. CPersIndex * pDstIndex = new CPersIndex( storage,
  760. wid,
  761. GetId(),
  762. _xPhysIndex->PageSize(),
  763. IsMaster() ? eMaster : eShadow );
  764. XPtr<CPersIndex> xDstIndex( pDstIndex );
  765. //
  766. // Make a backup copy of the stream.
  767. //
  768. _xPhysIndex->MakeBackupCopy( pDstIndex->_xPhysIndex.GetReference(),
  769. tracker );
  770. // Make a backup copy of the directory.
  771. //
  772. _xDir->MakeBackupCopy( storage, tracker );
  773. }
  774. #if CIDBG == 1
  775. //+---------------------------------------------------------------------------
  776. //
  777. // Member: CDiskIndex::VerifyContents, public
  778. //
  779. // Synopsis: Walks through an index and thus verifies each key
  780. //
  781. // History: 28-Oct-94 DwightKr Created
  782. //
  783. //----------------------------------------------------------------------------
  784. void CDiskIndex::VerifyContents()
  785. {
  786. //
  787. // Turn this on when we think we are missing keys.
  788. //
  789. #if 0
  790. CKeyCursor *pCursor = QueryCursor();
  791. if ( pCursor )
  792. {
  793. TRY
  794. {
  795. ciDebugOut((DEB_ITRACE, "Verifying contents of new index\n"));
  796. WCHAR FirstLetter = '@';
  797. for ( const CKeyBuf * pKey = pCursor->GetKey();
  798. pKey != NULL; pKey = pCursor->GetNextKey())
  799. {
  800. if ( *(pKey->GetStr()) != FirstLetter )
  801. {
  802. FirstLetter = *(pKey->GetStr());
  803. if ( FirstLetter < L'~' )
  804. ciDebugOut(( DEB_NOCOMPNAME | DEB_ITRACE | DEB_PENDING, "%c",
  805. FirstLetter ));
  806. else
  807. ciDebugOut(( DEB_NOCOMPNAME | DEB_ITRACE | DEB_PENDING, "<%04x>",
  808. FirstLetter ));
  809. }
  810. }
  811. ciDebugOut(( DEB_NOCOMPNAME | DEB_ITRACE | DEB_PENDING, "\n" ));
  812. }
  813. CATCH (CException, e)
  814. {
  815. ciDebugOut(( DEB_ERROR, "Error 0x%x while verifying contents of new index\n", e.GetErrorCode() ));
  816. }
  817. END_CATCH
  818. delete pCursor;
  819. }
  820. #endif // 0
  821. }
  822. #endif