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.

1095 lines
29 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: keylist.cxx
  7. //
  8. // Contents: KeyList
  9. //
  10. // History: 17-Feb-1994 KyleP Created
  11. //
  12. //--------------------------------------------------------------------------
  13. #include <pch.cxx>
  14. #pragma hdrstop
  15. #include <pidxtbl.hxx>
  16. #include <pdir.hxx>
  17. #include <cifailte.hxx>
  18. #include "keylist.hxx"
  19. #include "pcomp.hxx"
  20. #include "keyhash.hxx"
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Member: CKeyList::GetNextIid, public
  24. //
  25. // Synopsis: Returns the next valid index id for a new keylist.
  26. //
  27. // History: 31-Oct-93 w-PatG Created.
  28. //
  29. //----------------------------------------------------------------------------
  30. INDEXID CKeyList::GetNextIid ()
  31. {
  32. CIndexId CurId = GetId();
  33. if (!CurId.IsPersistent() || CurId.PersId() == MAX_PERS_ID)
  34. return CIndexId( 1, partidKeyList );
  35. else
  36. return CIndexId( CurId.PersId() + 1, partidKeyList );
  37. }
  38. //+-------------------------------------------------------------------------
  39. //
  40. // Method: CKeyList::FillRecord
  41. //
  42. // Synopsis: Creates index record for keylist
  43. //
  44. // Arguments: [record] -- Record to initialize
  45. //
  46. // History: 17-Feb-1994 KyleP Created
  47. //
  48. //--------------------------------------------------------------------------
  49. void CKeyList::FillRecord (CIndexRecord& record) const
  50. {
  51. record._objectId = ObjectId();
  52. record._iid = GetId();
  53. record._type = itKeyList;
  54. record._maxWorkId = MaxWorkId();
  55. }
  56. #ifdef KEYLIST_ENABLED
  57. //+---------------------------------------------------------------------------
  58. //
  59. // Member: CKeyList::Size, public
  60. //
  61. // Synopsis: Returns number of pages in Physical Index.
  62. //
  63. // History: 28-Oct-93 w-PatG Created.
  64. //
  65. //----------------------------------------------------------------------------
  66. unsigned CKeyList::Size() const
  67. {
  68. if ( _pPhysIndex )
  69. return _pPhysIndex->PageSize();
  70. else
  71. return 0;
  72. }
  73. //+---------------------------------------------------------------------------
  74. //
  75. // Member: CKeyList::CKeyList, public
  76. //
  77. // Synopsis: Default Constructor for CKeyList
  78. //
  79. // Effects: Creates a dummy KeyList
  80. //
  81. // History: 17-Dec-93 w-PatG Created.
  82. //
  83. // Note: The first kid/widMax in a keyList is set to 1 here, since
  84. // kids overlap in memory with pids, and pid 0, & 1 are reserved.
  85. //
  86. //----------------------------------------------------------------------------
  87. CKeyList::CKeyList()
  88. : CIndex( CIndexId( partidKeyList, MAX_PERS_ID + 1), 1, FALSE ),
  89. _sigKeyList(eSigKeyList),
  90. _pstorage(0),
  91. _obj(0),
  92. _pPhysIndex(0),
  93. _pPhysHash(0),
  94. _pDir(0)
  95. {
  96. ciDebugOut(( DEB_KEYLIST, "Open null keylist\n" ));
  97. }
  98. //+---------------------------------------------------------------------------
  99. //
  100. // Member: CKeyList::CKeyList, public
  101. //
  102. // Synopsis: Constructor for CKeyList
  103. //
  104. // Effects: Initializes KeyList from disk
  105. //
  106. // Arguments: [id] -- List ID of the key list.
  107. // [widMax] -- maximum work id
  108. //
  109. // History: 03-Nov-93 w-PatG Created.
  110. // 17-Feb-94 KyleP Initial version
  111. //
  112. //----------------------------------------------------------------------------
  113. CKeyList::CKeyList( PStorage & storage, WORKID objectId, INDEXID iid,
  114. KEYID kidMax )
  115. : CIndex( iid, kidMax, FALSE ),
  116. _sigKeyList(eSigKeyList),
  117. _pstorage(&storage),
  118. _obj ( storage.QueryObject(objectId) ),
  119. _pPhysIndex(0),
  120. _pPhysHash(0),
  121. _pDir(0)
  122. {
  123. ciDebugOut(( DEB_KEYLIST, "Open keylist 0x%x\n", iid ));
  124. TRY
  125. {
  126. //
  127. // Open the keylist index stream.
  128. //
  129. PMmStream * pStream = storage.QueryExistingIndexStream( _obj.GetObj(),
  130. PStorage::eOpenForRead );
  131. XPtr<PMmStream> sStream( pStream );
  132. _pPhysIndex = new CPhysIndex ( storage, _obj.GetObj(), objectId,
  133. PStorage::eOpenForRead,
  134. sStream );
  135. //
  136. // Open the keylist hash stream.
  137. //
  138. pStream = storage.QueryExistingHashStream( _obj.GetObj(),
  139. PStorage::eOpenForRead );
  140. sStream.Set( pStream );
  141. _pPhysHash = new CPhysHash ( storage, _obj.GetObj(), objectId,
  142. PStorage::eOpenForRead,
  143. sStream );
  144. //
  145. // Open the directory.
  146. //
  147. _pDir = storage.QueryExistingDirectory ( _obj.GetObj(), PStorage::eOpenForRead );
  148. }
  149. CATCH ( CException, e )
  150. {
  151. delete _pDir;
  152. delete _pPhysHash;
  153. delete _pPhysIndex;
  154. RETHROW();
  155. }
  156. END_CATCH
  157. }
  158. //+---------------------------------------------------------------------------
  159. //
  160. // Member: CWKeyList::CWKeyList, public
  161. //
  162. // Synopsis: Create an empty writeable index
  163. //
  164. // Arguments: [storage] -- physical storage
  165. //
  166. // History: 03-Apr-91 BartoszM Created.
  167. // 17-Feb-93 KyleP Initial version
  168. //
  169. //----------------------------------------------------------------------------
  170. CWKeyList::CWKeyList ( PStorage & storage, WORKID objectId, INDEXID iid,
  171. unsigned size, CKeyList * pOldKeyList )
  172. : CKeyList( storage, objectId, iid, pOldKeyList->MaxWorkId(), 0 ),
  173. _sigWKeyList(eSigWKeyList),
  174. _pOldKeyCursor( 0),
  175. _pKeyComp( 0 ),
  176. _ulPage( 0xFFFFFFFF )
  177. {
  178. ciDebugOut(( DEB_KEYLIST, "Create keylist 0x%x\n", iid ));
  179. _keyLast.SetCount(0);
  180. TRY
  181. {
  182. //open a physindex size=1
  183. PMmStream * pStream = storage.QueryNewIndexStream( _obj.GetObj(),
  184. FALSE // not a master
  185. );
  186. XPtr<PMmStream> sStream(pStream);
  187. _pPhysIndex = new CPhysIndex( storage, _obj.GetObj(),
  188. objectId, size, sStream );
  189. Win4Assert( !sStream );
  190. pStream = storage.QueryNewHashStream( _obj.GetObj() );
  191. sStream.Set(pStream);
  192. _pPhysHash = new CPhysHash ( storage, _obj.GetObj(), objectId, 0,
  193. sStream );
  194. Win4Assert( !sStream );
  195. ciFAILTEST( STATUS_DISK_FULL );
  196. _pDir = storage.QueryNewDirectory ( _obj.GetObj() );
  197. _pKeyComp = new CKeyComp( *_pPhysIndex, widInvalid, FALSE );
  198. _pKeyComp->WriteFirstKeyFull();
  199. _pOldKeyCursor = pOldKeyList->QueryCursor();
  200. }
  201. CATCH ( CException, e )
  202. {
  203. delete _pKeyComp;
  204. RETHROW();
  205. }
  206. END_CATCH
  207. }
  208. //+---------------------------------------------------------------------------
  209. //
  210. // Function: CWKeyList - Ctor
  211. //
  212. // Synopsis: A writable key list constructor used when re-starting a
  213. // paused master merge.
  214. //
  215. // Effects:
  216. //
  217. // Arguments: [storage] -- Storage object.
  218. // [objectId] -- ObjectId of the new key list.
  219. // [iid] -- IndexId of the new key list.
  220. // [pOldKeyList] -- Pointer to the old key list.
  221. // [splitKey] -- The last key that is guaranteed to be
  222. // written to disk in the split key. If none were written,
  223. // this will be set to "MinKey".
  224. //
  225. // History: 4-20-94 srikants Created
  226. //
  227. // Notes:
  228. //
  229. //----------------------------------------------------------------------------
  230. CWKeyList::CWKeyList ( PStorage & storage, WORKID objectId, INDEXID iid,
  231. CKeyList * pOldKeyList,
  232. CKeyBuf & splitKey,
  233. WORKID widMax )
  234. : CKeyList( storage, objectId, iid, widMax, 0 ),
  235. _sigWKeyList(eSigWKeyList),
  236. _pOldKeyCursor( 0),
  237. _pKeyComp( 0 ),
  238. _ulPage( 0xFFFFFFFF )
  239. {
  240. ciDebugOut(( DEB_KEYLIST, "Restart keylist 0x%x\n", iid ));
  241. Win4Assert( widMax >= pOldKeyList->MaxWorkId() );
  242. _keyLast.SetCount(0);
  243. TRY
  244. {
  245. //
  246. // Open existing IndexStream, HashStream and Directory stream
  247. // for write access.
  248. //
  249. PMmStream * pStream = storage.QueryExistingIndexStream( _obj.GetObj(),
  250. PStorage::eOpenForWrite );
  251. XPtr<PMmStream> sStream(pStream);
  252. _pPhysIndex = new CPhysIndex( storage, _obj.GetObj(), objectId,
  253. PStorage::eOpenForWrite,
  254. sStream
  255. );
  256. pStream = storage.QueryExistingHashStream( _obj.GetObj(),
  257. PStorage::eOpenForWrite );
  258. sStream.Set( pStream );
  259. _pPhysHash = new CPhysHash ( storage, _obj.GetObj(), objectId,
  260. PStorage::eOpenForWrite,
  261. sStream
  262. );
  263. ciFAILTEST( STATUS_DISK_FULL );
  264. _pDir = storage.QueryExistingDirectory ( _obj.GetObj(),
  265. PStorage::eOpenForWrite
  266. );
  267. //
  268. // Restore the existing directory by reading from the beginning
  269. // upto the split key.
  270. //
  271. BitOffset beginBitOff, endBitOff;
  272. RestoreDirectory( splitKey, beginBitOff, endBitOff );
  273. //
  274. // Create a key compressor which can understand partially filled
  275. // pages and position to write the next key provided.
  276. //
  277. _pKeyComp = new CKeyComp( *_pPhysIndex, widInvalid,
  278. endBitOff, beginBitOff,
  279. splitKey,
  280. FALSE // don't use links
  281. );
  282. _pKeyComp->WriteFirstKeyFull();
  283. //
  284. // Update the used pages count in the index.
  285. //
  286. _pPhysIndex->SetUsedPagesCount( endBitOff.Page() + 1 );
  287. //
  288. // Set up the existing keylist cursor to position after the
  289. // split key.
  290. //
  291. if ( splitKey.IsMinKey() )
  292. {
  293. _pOldKeyCursor = pOldKeyList->QueryCursor();
  294. }
  295. else
  296. {
  297. CKey Key( splitKey );
  298. _pOldKeyCursor = (CKeyDeComp *) pOldKeyList->QueryCursor( &Key );
  299. if ( _pOldKeyCursor )
  300. {
  301. CKeyBuf const * pTemp = _pOldKeyCursor->GetKey();
  302. if ( pTemp && (pTemp->CompareStr( splitKey ) == 0) )
  303. {
  304. _pOldKeyCursor->GetNextKey();
  305. }
  306. }
  307. _keyLast = splitKey;
  308. }
  309. }
  310. CATCH ( CException, e )
  311. {
  312. delete _pKeyComp;
  313. RETHROW();
  314. }
  315. END_CATCH
  316. }
  317. //+---------------------------------------------------------------------------
  318. //
  319. // Function: RestoreDirectory
  320. //
  321. // Synopsis: Restores the directory object from the keys added to the
  322. // key list in the previous invocation of master merge.
  323. //
  324. // Effects:
  325. //
  326. // Arguments: [splitKey] -- The key that is known to be successfully
  327. // writtent to disk.
  328. // [beginBitOff] -- Output - beginning offset of the split
  329. // key.
  330. // [endBitOff] -- Output - end offset+1 (bit) of the split
  331. // key. This is the place where the next key should be written.
  332. //
  333. // History: 4-20-94 srikants Created
  334. //
  335. // Notes: The "Pid" field in the key is used by the keylist as a
  336. // "KeyId" and it is a monotonically increasing entity. Each
  337. // key has a unique "KeyId" and so as part of restore, we have
  338. // to get the last "KeyId" used thus far.
  339. //
  340. //----------------------------------------------------------------------------
  341. void CWKeyList::RestoreDirectory( CKeyBuf & splitKey,
  342. BitOffset & beginBitOff,
  343. BitOffset & endBitOff )
  344. {
  345. Win4Assert( _pDir );
  346. Win4Assert( _pPhysIndex );
  347. beginBitOff.Init(0,0);
  348. endBitOff.Init(0,0);
  349. // STACKSTACK
  350. XPtr<CKeyBuf> xKeyLast(new CKeyBuf()); // initialized to min key
  351. //
  352. // Remove all keys in the directory after the split key.
  353. //
  354. xKeyLast->FillMin();
  355. _pDir->DeleteKeysAfter( xKeyLast.GetReference() );
  356. //
  357. // "MinKey" is a special case and must be dealt with by assuming
  358. // that no key was written out.
  359. //
  360. if ( splitKey.IsMinKey() )
  361. return;
  362. CKeyDeComp decomp( *_pDir, GetId() ,
  363. *_pPhysIndex, widInvalid,
  364. FALSE, // Don't use links.
  365. FALSE // Don't use directory.
  366. );
  367. const CKeyBuf * pKey;
  368. #if CIDBG == 1
  369. xKeyLast->SetPid(pidContents); // arbitrary but not pidAll
  370. #endif
  371. for ( pKey = decomp.GetKey() ;
  372. 0 != pKey;
  373. pKey = decomp.GetNextKey(&beginBitOff) )
  374. {
  375. if ( pKey->Pid() > _widMax )
  376. {
  377. _widMax = pKey->Pid();
  378. }
  379. if ( beginBitOff.Page() != _ulPage &&
  380. !AreEqualStr(pKey, xKeyLast.GetPointer()))
  381. {
  382. _ulPage = beginBitOff.Page();
  383. _pDir->Add ( beginBitOff, *pKey );
  384. }
  385. if ( pKey->CompareStr(splitKey) >= 0 )
  386. {
  387. ciDebugOut(( DEB_ITRACE, "RestoreDirectory - SplitKey Found \n" ));
  388. break;
  389. }
  390. xKeyLast.GetReference() = *pKey;
  391. }
  392. if ( 0 != pKey )
  393. {
  394. splitKey = *pKey;
  395. }
  396. else {
  397. splitKey = xKeyLast.GetReference();
  398. }
  399. decomp.GetOffset( endBitOff );
  400. //
  401. // Need to skip the current key cursor until the last key
  402. //
  403. ciDebugOut(( DEB_ITRACE, "KeyList - Restart KeyId 0x%x\n", _widMax ));
  404. ciDebugOut(( DEB_ITRACE, "Keylist Restart split key is '%ws'\n",
  405. splitKey.GetStr() ));
  406. ciDebugOut(( DEB_ITRACE, "Keylist Restart page:offset = 0x%x:0x%x\n",
  407. endBitOff.Page(), endBitOff.Offset() ));
  408. }
  409. //+---------------------------------------------------------------------------
  410. //
  411. // Member: CKeyList::~CKeyList, public
  412. //
  413. // Synopsis: Destructor
  414. //
  415. // Effects: Release all memory used by keylist
  416. //
  417. // History: 31-Oct-93 w-PatG Created.
  418. // 17-Feb-94 KyleP Initial version
  419. //
  420. //----------------------------------------------------------------------------
  421. CKeyList::~CKeyList()
  422. {
  423. delete _pDir;
  424. delete _pPhysHash;
  425. delete _pPhysIndex;
  426. }
  427. //+-------------------------------------------------------------------------
  428. //
  429. // Method: CWKeyList::CWKeyList
  430. //
  431. // Synopsis: Dtor for writeable keylist
  432. //
  433. // History: 17-Feb-1994 KyleP Created
  434. //
  435. //--------------------------------------------------------------------------
  436. CWKeyList::~CWKeyList()
  437. {
  438. delete _pOldKeyCursor;
  439. delete _pKeyComp;
  440. }
  441. //+---------------------------------------------------------------------------
  442. //
  443. // Member: CKeyList::QueryCursor, public
  444. //
  445. // Synopsis: Create a cursor for the KeyList
  446. //
  447. // Effects: Creates a cursor
  448. //
  449. // Returns: A pointer to a CKeyCursor.
  450. //
  451. // History: 31-Oct-93 w-PatG Created.
  452. // 17-Feb-94 KyleP Initial version
  453. //
  454. //----------------------------------------------------------------------------
  455. CKeyCursor * CKeyList::QueryCursor()
  456. {
  457. if(_pPhysIndex == 0)
  458. {
  459. return(0);
  460. }
  461. else
  462. {
  463. BitOffset posKey;
  464. CKey key;
  465. key.FillMin();
  466. CKeyBuf keyInit;
  467. _pDir->Seek ( key, &keyInit, posKey );
  468. ciDebugOut (( DEB_ITRACE, "found key %.*ws at %lx:%lx\n",
  469. keyInit.StrLen(), keyInit.GetStr(),
  470. posKey.Page(), posKey.Offset() ));
  471. CKeyDeComp* pCursor = new CKeyDeComp(
  472. *_pDir, GetId(), *_pPhysIndex, posKey, keyInit, &key, _widMax, FALSE );
  473. if ( pCursor->GetKey() == 0 )
  474. {
  475. delete pCursor;
  476. pCursor = 0;
  477. }
  478. return pCursor;
  479. }
  480. }
  481. //+---------------------------------------------------------------------------
  482. //
  483. // Member: CKeyList::QueryCursor, public
  484. //
  485. // Synopsis: Create a cursor for the KeyList
  486. //
  487. // Effects: Creates a cursor
  488. //
  489. // Arguments: [pkey] -- Key to search for
  490. //
  491. // Returns: A pointer to a CKeyCursor.
  492. //
  493. // History: 31-Oct-93 w-PatG Created.
  494. //
  495. //----------------------------------------------------------------------------
  496. COccCursor * CKeyList::QueryCursor( CKey const * pkey,
  497. BOOL isRange,
  498. ULONG & cMaxNodes )
  499. {
  500. Win4Assert( cMaxNodes > 0 );
  501. if(_pPhysIndex == 0)
  502. return( 0 );
  503. if (isRange)
  504. {
  505. CKey keyEnd;
  506. keyEnd.FillMax (*pkey);
  507. return QueryRangeCursor (pkey, &keyEnd, cMaxNodes );
  508. }
  509. cMaxNodes--;
  510. if ( 0 == cMaxNodes )
  511. {
  512. ciDebugOut(( DEB_WARN, "Node limit reached in CKeyList::QueryCursor\n" ));
  513. THROW( CException( STATUS_TOO_MANY_NODES ) );
  514. }
  515. BitOffset posKey;
  516. CKeyBuf keyInit;
  517. _pDir->Seek ( *pkey, &keyInit, posKey );
  518. ciDebugOut (( DEB_KEYLIST, "found key %.*ws at %lx:%lx\n",
  519. keyInit.StrLen(), keyInit.GetStr(),
  520. posKey.Page(), posKey.Offset() ));
  521. CKeyDeComp* pCursor = new CKeyDeComp(
  522. *_pDir, GetId(), *_pPhysIndex, posKey, keyInit, pkey, _widMax, FALSE );
  523. if ( pCursor->GetKey() == 0 )
  524. {
  525. delete pCursor;
  526. pCursor = 0;
  527. }
  528. return pCursor;
  529. }
  530. //+-------------------------------------------------------------------------
  531. //
  532. // Method: CKeyList::QueryRangeCursor
  533. //
  534. // Synopsis: Not (yet) implemented for KeyList
  535. //
  536. // Arguments: [pkeyBegin] -- Beginning of range
  537. // [pkeyEnd] -- End of range
  538. //
  539. // Returns: Cursor
  540. //
  541. // History: 17-Feb-1994 KyleP Created
  542. //
  543. //--------------------------------------------------------------------------
  544. COccCursor * CKeyList::QueryRangeCursor( const CKey * pkeyBegin,
  545. const CKey * pkeyEnd,
  546. ULONG & cMaxNodes )
  547. {
  548. return( 0 );
  549. }
  550. //+-------------------------------------------------------------------------
  551. //
  552. // Method: CKeyList::QuerySynCursor
  553. //
  554. // Synopsis: Never implemented for KeyList
  555. //
  556. // Arguments: [keyArr] -- Array of keys to merge
  557. // [isRange] -- True if ???
  558. //
  559. // Returns: Cursor
  560. //
  561. // History: 17-Feb-1994 KyleP Created
  562. //
  563. //--------------------------------------------------------------------------
  564. COccCursor * CKeyList::QuerySynCursor( CKeyArray & keyArr,
  565. BOOL isRange,
  566. ULONG & cMaxNodes )
  567. {
  568. Win4Assert( !"CKeyList::QuerySynCursor -- Illegal call" );
  569. return( 0 );
  570. }
  571. //+-------------------------------------------------------------------------
  572. //
  573. // Method: CKeyList::Close
  574. //
  575. // Synopsis: Close persistent resources
  576. //
  577. // History: 17-Feb-1994 KyleP Created
  578. //
  579. //--------------------------------------------------------------------------
  580. void CKeyList::Close()
  581. {
  582. if ( _pDir )
  583. _pDir->Close();
  584. if ( _pPhysHash )
  585. _pPhysHash->Close();
  586. if ( _pPhysIndex )
  587. _pPhysIndex->Close();
  588. }
  589. //+---------------------------------------------------------------------------
  590. //
  591. // Member: CKeyList::Remove, public
  592. //
  593. // Synopsis: Remove index from storage
  594. //
  595. // History: 02-May-91 BartoszM Created.
  596. // 16-Dec-93 w-PatG Stolen from pindex.
  597. // 28-Jun-94 SrikantS Modified it to not throw
  598. // exceptions.
  599. //
  600. //----------------------------------------------------------------------------
  601. void CKeyList::Remove()
  602. {
  603. if ( _pPhysIndex )
  604. {
  605. Close();
  606. _obj->Close();
  607. if ( !_pstorage->RemoveObject( ObjectId() ) )
  608. {
  609. Win4Assert( !"delete of index failed" );
  610. ciDebugOut(( DEB_ERROR, "Delete of index %08x failed: %d\n",
  611. ObjectId(), GetLastError() ));
  612. }
  613. }
  614. }
  615. //+---------------------------------------------------------------------------
  616. //
  617. // Member: CKeyList::KeyToId, public
  618. //
  619. // Synopsis: Maps from a key to an id.
  620. //
  621. // Arguments: [pkey] -- pointer to the key to be mapped to ULONG
  622. //
  623. // Returns: key id - a ULONG
  624. //
  625. // History: 31-Oct-93 w-PatG Created.
  626. // 17-Feb-94 KyleP Initial version
  627. //
  628. // Notes: KeyToId searches for key in index and returns the pid as
  629. // the key id (kid).
  630. //
  631. //----------------------------------------------------------------------------
  632. KEYID CKeyList::KeyToId( CKey const * pkey )
  633. {
  634. //
  635. // These keys must be just a [normalized] word. No string/value id in
  636. // front of them.
  637. //
  638. Win4Assert( pkey->Pid() == 0 );
  639. KEYID kid;
  640. if(_pPhysIndex == 0)
  641. kid = kidInvalid;
  642. else
  643. {
  644. BitOffset posKey;
  645. CKeyBuf keyInit;
  646. _pDir->Seek ( *pkey, &keyInit, posKey );
  647. ciDebugOut (( DEB_KEYLIST, "found key %.*ws at %lx:%lx\n",
  648. keyInit.StrLen(), keyInit.GetStr(),
  649. posKey.Page(), posKey.Offset() ));
  650. CKeyDeComp cur( *_pDir, GetId(), *_pPhysIndex, posKey, keyInit,
  651. pkey, _widMax, FALSE );
  652. CKeyBuf const * pkey2 = cur.GetKey();
  653. if ( pkey2 == 0 || pkey->CompareStr( *pkey2 ) != 0 )
  654. {
  655. kid = kidInvalid;
  656. }
  657. else
  658. {
  659. kid = pkey2->Pid();
  660. }
  661. }
  662. ciDebugOut(( DEB_KEYLIST, "Key \"%.*ws\" --> id %d\n",
  663. pkey->Count()/sizeof(WCHAR), pkey->GetBuf(),
  664. kid ));
  665. return( kid );
  666. }
  667. //+---------------------------------------------------------------------------
  668. //
  669. // Member: CKeyList::IdToKey, public
  670. //
  671. // Synopsis: Maps an id to a key.
  672. //
  673. // Arguments: [ulKid] -- key id to mapped to a key
  674. // [rkey] -- the mapped key
  675. //
  676. // History: 31-Oct-93 w-PatG Created.
  677. // 17-Feb-94 KyleP Initial version
  678. //
  679. // Notes: IdToKey uses the key hash to locate the correct leaf page in
  680. // the directory, then locates that leaf page and initializes
  681. // a cursor into the index. The search then proceeds until a
  682. // key with the matching key id is located or no more keys are
  683. // found.
  684. //
  685. //----------------------------------------------------------------------------
  686. BOOL CKeyList::IdToKey( KEYID kid, CKey & rkey )
  687. {
  688. if ( 0 == _pPhysHash )
  689. return( FALSE );
  690. if ( kid == 0 || kid > MaxKeyIdInUse() )
  691. return( FALSE );
  692. CRKeyHash KeyHash( *_pPhysHash, _pPhysIndex->PageSize() );
  693. CKeyBuf keyInit;
  694. keyInit.FillMin();
  695. BitOffset posKey;
  696. KeyHash.Find( kid, posKey );
  697. CKey key;
  698. CKeyDeComp cur( *_pDir, GetId(), *_pPhysIndex, posKey,
  699. keyInit, &key, _widMax, FALSE );
  700. for ( CKeyBuf const * pkey = cur.GetKey();
  701. pkey && pkey->Pid() != kid;
  702. pkey = cur.GetNextKey() )
  703. continue; // Null body
  704. if ( pkey )
  705. rkey = *pkey;
  706. else
  707. {
  708. Win4Assert( !"Can't find key!" );
  709. return( FALSE );
  710. }
  711. ciDebugOut(( DEB_KEYLIST, "id %d --> Key \"%.*ws\"\n",
  712. kid, pkey->StrLen(), pkey->GetStr() ));
  713. return( TRUE );
  714. }
  715. //+-------------------------------------------------------------------------
  716. //
  717. // Method: CWKeyList::PutKey
  718. //
  719. // Synopsis: Store new key in keylist
  720. //
  721. // Effects: Copies all old keys <= [pKeyAdd] to keylist and then adds
  722. // [pkeyAdd] if it does not yet exist.
  723. //
  724. // Arguments: [pkeyAdd] -- Key to add
  725. //
  726. // History: 17-Feb-1994 KyleP Created
  727. //
  728. //--------------------------------------------------------------------------
  729. KEYID CWKeyList::PutKey( CKeyBuf const * pkeyAdd, BitOffset & bitOff )
  730. {
  731. Win4Assert( _pKeyComp );
  732. KEYID kid;
  733. //
  734. // Only store content keys. No value keys.
  735. //
  736. if ( *(pkeyAdd->GetBuf()) != STRING_KEY )
  737. return kidInvalid;
  738. //
  739. // Write keys from old keylist that are <= current key.
  740. //
  741. if ( _pOldKeyCursor )
  742. for ( CKeyBuf const * pkey = _pOldKeyCursor->GetKey();
  743. pkey && pkey->CompareStr(*pkeyAdd) <= 0;
  744. pkey = _pOldKeyCursor->GetNextKey() )
  745. {
  746. ciDebugOut(( DEB_KEYLIST, "Keylist: Copy Key \"%.*ws\" -- keyid = %d\n",
  747. pkey->StrLen(), pkey->GetStr(), pkey->Pid() ));
  748. _keyLast = *pkey;
  749. _pKeyComp->PutKey( &_keyLast, bitOff );
  750. if ( bitOff.Page() != _ulPage )
  751. {
  752. _ulPage = bitOff.Page();
  753. _pDir->Add ( bitOff, _keyLast );
  754. }
  755. }
  756. //
  757. // Write this key?
  758. //
  759. if ( _keyLast.CompareStr( *pkeyAdd ) < 0 )
  760. {
  761. _keyLast = *pkeyAdd;
  762. _keyLast.SetPid( GetKeyId() );
  763. kid = _keyLast.Pid();
  764. ciDebugOut(( DEB_KEYLIST, "Keylist: Add Key \"%.*ws\" -- keyid = %d\n",
  765. _keyLast.StrLen(), _keyLast.GetStr(), _keyLast.Pid() ));
  766. _pKeyComp->PutKey( &_keyLast, bitOff );
  767. if ( bitOff.Page() != _ulPage )
  768. {
  769. _ulPage = bitOff.Page();
  770. _pDir->Add ( bitOff, _keyLast );
  771. }
  772. }
  773. else
  774. {
  775. kid = _keyLast.Pid();
  776. }
  777. return kid;
  778. }
  779. //+-------------------------------------------------------------------------
  780. //
  781. // Method: CWKeyList::Done
  782. //
  783. // Synopsis: Finish writing keylist + build hash
  784. //
  785. // Effects: Copy any remaining keys from old keylist and build hash
  786. // table. Reopen for read access.
  787. //
  788. // History: 17-Feb-1994 KyleP Created
  789. //
  790. //--------------------------------------------------------------------------
  791. void CWKeyList::Done( BOOL & fAbort )
  792. {
  793. ciDebugOut(( DEB_KEYLIST, "KeyList::Done\n" ));
  794. //
  795. // Write remaining keys from old keylist;
  796. //
  797. BitOffset bitOff;
  798. if ( _pOldKeyCursor )
  799. for ( CKeyBuf const * pkey = _pOldKeyCursor->GetKey();
  800. pkey && pkey->Count() > 0 && pkey->CompareStr( _keyLast ) > 0;
  801. pkey = _pOldKeyCursor->GetNextKey() )
  802. {
  803. ciDebugOut(( DEB_KEYLIST, "Keylist: Copy Key \"%.*ws\" -- keyid = %d\n",
  804. pkey->StrLen(), pkey->GetStr(), pkey->Pid() ));
  805. _keyLast = *pkey;
  806. _pKeyComp->PutKey( &_keyLast, bitOff);
  807. if ( bitOff.Page() != _ulPage )
  808. {
  809. _ulPage = bitOff.Page();
  810. _pDir->Add ( bitOff, _keyLast );
  811. }
  812. }
  813. //
  814. // Add sentinel key
  815. //
  816. _keyLast.FillMax();
  817. _keyLast.SetPid(1);
  818. _pKeyComp->PutKey( &_keyLast, bitOff );
  819. //
  820. // Add sentinel key to the directory.
  821. //
  822. _pDir->Add( bitOff, _keyLast );
  823. //
  824. // Close compressor, decompressor and directory
  825. //
  826. delete _pOldKeyCursor;
  827. _pOldKeyCursor = 0;
  828. delete _pKeyComp;
  829. _pKeyComp = 0;
  830. // STACKSTACK
  831. XPtr<CKeyBuf> xMaxKey(new CKeyBuf());
  832. xMaxKey->FillMax();
  833. _pDir->LokFlushDir(xMaxKey.GetReference());
  834. _pDir->LokBuildDir(xMaxKey.GetReference());
  835. //
  836. // Reopen for read access
  837. //
  838. _pPhysIndex->Flush();
  839. _pPhysIndex->Reopen();
  840. //
  841. // Rescan to build hash table
  842. //
  843. BuildHash( fAbort );
  844. _pPhysHash->Flush();
  845. _pPhysHash->Reopen();
  846. }
  847. //+-------------------------------------------------------------------------
  848. //
  849. // Method: CWKeyList::BuildHash
  850. //
  851. // Synopsis: Build KeyHash
  852. //
  853. // History: 17-Feb-1994 KyleP Created
  854. // 15-Aug-1994 SrikantS Modified not to use the directory
  855. // iterator
  856. //
  857. //--------------------------------------------------------------------------
  858. void CWKeyList::BuildHash( BOOL & fAbort )
  859. {
  860. CWKeyHash keyhash( *_pPhysHash, _pPhysIndex->PageSize(), MaxKeyIdInUse() );
  861. #if defined(CI_KEYHASH)
  862. CKeyDeComp * pcur = (CKeyDeComp *) QueryCursor();
  863. if ( 0 == pcur )
  864. {
  865. return;
  866. }
  867. BitOffset hashOff; // Offset written in the hash table for kids.
  868. BitOffset keyOff; // Offset of the current key.
  869. hashOff.Init(0,0);
  870. keyOff.Init(0,0);
  871. #if CIDBG==1
  872. unsigned cKey = 0;
  873. #endif // CIDBG==1
  874. for ( const CKeyBuf * pkey = pcur->GetKey(); 0 != pkey;
  875. pkey = pcur->GetNextKey( &keyOff ) )
  876. {
  877. if ( fAbort )
  878. {
  879. fAbort = FALSE;
  880. THROW( CException( STATUS_TOO_LATE ) );
  881. }
  882. //
  883. // Check if the current key starts on a different page from
  884. // the previous one. If so, we have to update the offset
  885. // that is written to the hash stream.
  886. //
  887. if ( keyOff.Page() != hashOff.Page() )
  888. {
  889. Win4Assert( keyOff.Page() > hashOff.Page() );
  890. hashOff.Init( keyOff.Page(), keyOff.Offset() );
  891. }
  892. keyhash.Add( pkey->Pid(), hashOff );
  893. #if CIDBG==1
  894. cKey++;
  895. #endif // CIDBG==1
  896. ciDebugOut(( DEB_KEYLIST, "Hash: index %d, key %.*ws (kid = %d)\n",
  897. hashOff.Page(),
  898. pkey->StrLen(),
  899. pkey->GetStr(),
  900. pkey->Pid() ));
  901. }
  902. delete pcur;
  903. #endif // CI_KEYHASH
  904. }
  905. #else // !KEYLIST_ENABLED
  906. CKeyList::CKeyList()
  907. : CIndex( CIndexId( partidKeyList, MAX_PERS_ID + 1), 1, FALSE )
  908. {
  909. ciDebugOut(( DEB_KEYLIST, "Open null keylist\n" ));
  910. }
  911. CKeyList::CKeyList( KEYID kidMax, INDEXID iid )
  912. : CIndex( iid, kidMax, FALSE )
  913. {
  914. }
  915. #endif // !KEYLIST_ENABLED