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.

573 lines
17 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 1998.
  5. //
  6. // File: mindex.hxx
  7. //
  8. // Contents: CMasterMergeIndex
  9. //
  10. // Classes: CMasterMergeIndex
  11. //
  12. // Functions:
  13. //
  14. // History: 8-17-94 srikants Created
  15. //
  16. //----------------------------------------------------------------------------
  17. #pragma once
  18. #include <pstore.hxx>
  19. #include <bitoff.hxx>
  20. #include "pindex.hxx"
  21. #include "physidx.hxx"
  22. #include "mmerglog.hxx"
  23. #include "bitstm.hxx"
  24. #include "pcomp.hxx"
  25. #include "pmcomp.hxx"
  26. #include <frmutils.hxx>
  27. class CFreshTest;
  28. class PDirectory;
  29. class CKeyCurStack;
  30. class CRSemiInfinitePage;
  31. class CKeyStack;
  32. class CIndexSnapshot;
  33. class CIndexRecord;
  34. class CWKeyList;
  35. class CTrackSplitKey;
  36. class CMPersDeComp;
  37. class CRWStore;
  38. class CPartition;
  39. //+---------------------------------------------------------------------------
  40. //
  41. // Function: CiPageToCommonPage
  42. //
  43. // Synopsis: Given a "CI Page" number, it computes the COMMON page on which
  44. // the ci page is.
  45. //
  46. // Arguments: [nCiPage] -- The CI page number.
  47. //
  48. // History: 4-20-94 srikants Created
  49. //
  50. // Notes:
  51. //
  52. //----------------------------------------------------------------------------
  53. inline ULONG CiPageToCommonPage( ULONG nCiPage )
  54. {
  55. return(nCiPage/PAGES_PER_COMMON_PAGE);
  56. }
  57. //+---------------------------------------------------------------------------
  58. //
  59. // Class: CSplitKeyInfo
  60. //
  61. // Purpose: A class for storing and retrieving information associated
  62. // with a split key.
  63. //
  64. // History: 4-20-94 srikants Created
  65. //
  66. //----------------------------------------------------------------------------
  67. class CSplitKeyInfo
  68. {
  69. public:
  70. CSplitKeyInfo();
  71. void SetBeginOffset( const BitOffset & bitOff )
  72. { _start = bitOff; }
  73. const BitOffset & GetBeginOffset () const
  74. { return _start; }
  75. void SetEndOffset( const BitOffset & bitOff )
  76. { _end = bitOff; }
  77. const BitOffset & GetEndOffset ( ) const
  78. { return _end; }
  79. void SetKey( const CKeyBuf & key )
  80. { _key = key; }
  81. const CKeyBuf & GetKey () const
  82. { return _key; }
  83. CSplitKeyInfo & operator=( const CSplitKeyInfo & rhs )
  84. {
  85. memcpy( this, &rhs, sizeof(CSplitKeyInfo) );
  86. return *this;
  87. }
  88. void SetMinKey() { _key.FillMin(); }
  89. WORKID GetWidMax() const { return _widMax; }
  90. void SetWidMax( WORKID widMax) { _widMax = widMax; }
  91. #ifdef CIEXTMODE
  92. void CiExtDump(void *ciExtSelf);
  93. #endif
  94. private:
  95. BitOffset _start; // Offset from where this key begins.
  96. BitOffset _end; // Offset where this key ends + 1.
  97. CKeyBuf _key; // The actual key.
  98. WORKID _widMax; // Maximum wid.
  99. };
  100. //+---------------------------------------------------------------------------
  101. //
  102. // Class: CTrackSplitKey
  103. //
  104. // Purpose: Tracks the split key during master merge. At any point
  105. // it can tell the key that can be used as a split key if
  106. // all the pages upto (not including the current one which
  107. // could be partially filled) is flushed to the disk. A key
  108. // qualifies to be a split key if it is on a page which never
  109. // needs to be written to after flushing; it must not be written
  110. // even for patching up the forward links in the bit stream.
  111. //
  112. // History: 4-12-94 srikants Created
  113. //
  114. //
  115. //----------------------------------------------------------------------------
  116. class CTrackSplitKey
  117. {
  118. public:
  119. CTrackSplitKey() : _fNewSplitKeyFound(FALSE) { }
  120. CTrackSplitKey( const CKeyBuf & splitKey,
  121. const BitOffset & bitoffBeginSplit,
  122. const BitOffset & bitoffEndSplit );
  123. void BeginNewKey( const CKeyBuf & currKey,
  124. const BitOffset & beginCurrOff,
  125. WORKID widMax = widInvalid );
  126. const CSplitKeyInfo & GetSplitKey( BitOffset & bitOffFlush )
  127. {
  128. bitOffFlush = _splitKey1.GetEndOffset();
  129. return(_splitKey2);
  130. }
  131. BOOL IsNewKeyFound() { return _fNewSplitKeyFound; }
  132. void ClearNewKeyFound() { _fNewSplitKeyFound = FALSE; }
  133. #ifdef CIEXTMODE
  134. void CiExtDump(void *ciExtSelf);
  135. #endif
  136. private:
  137. CSplitKeyInfo _splitKey2; // The "real" split key. Backpatching of
  138. // forward links is also completed for
  139. // this key.
  140. CSplitKeyInfo _splitKey1; // The key which will be the next split
  141. // key when back patching is completed.
  142. CSplitKeyInfo _prevKey; // The complete key which was looked at
  143. // last.
  144. CSplitKeyInfo _currKey; // The key being currently written by the
  145. // compressor.
  146. BOOL _fNewSplitKeyFound; // Was a splitkey found
  147. };
  148. //+---------------------------------------------------------------------------
  149. //
  150. // Class: STrackSplitKey
  151. //
  152. // Purpose: A smart pointer to a CTrackSplitKey object.
  153. //
  154. // History: 4-12-94 srikants Created
  155. //
  156. //----------------------------------------------------------------------------
  157. class STrackSplitKey
  158. {
  159. public:
  160. STrackSplitKey( CTrackSplitKey * pSplitKey ) : _pSplitKey(pSplitKey)
  161. {
  162. }
  163. ~STrackSplitKey() { delete _pSplitKey; }
  164. CTrackSplitKey * operator->() { return _pSplitKey; }
  165. CTrackSplitKey * Acquire()
  166. {
  167. CTrackSplitKey * pTemp = _pSplitKey;
  168. _pSplitKey = 0;
  169. return(_pSplitKey);
  170. }
  171. private:
  172. CTrackSplitKey * _pSplitKey;
  173. };
  174. //+---------------------------------------------------------------------------
  175. //
  176. // Class: CMasterMergeIndex
  177. //
  178. // Purpose: Encapsulates master index operations which span the current
  179. // master index and a new master index during a master merge.
  180. //
  181. // Interface:
  182. //
  183. // History: 30-Mar-94 DwightKr Created.
  184. // 23-Aug-94 SrikantS Modified to use a different model with
  185. // a target index and a target sink.
  186. //
  187. // Notes: CMasterMergeIndex is an encapsulation of the master index
  188. // while a master merge is in progress. A master merge is
  189. // considered to be in progress even when it is "paused".
  190. //
  191. // The _pTargetMasterIndex is the "evolving" target master which
  192. // will become the new master index after the merge is complete.
  193. // It participates in queries. The _pTargetSink is a physical
  194. // "write only" index to which "keys+data" are added. When we
  195. // checkpoint during a merge, all the keys before and including
  196. // the "current split key" are "transferred" to the
  197. // _pTargetMasterIndex from the _pTargetSink. Eventually all the
  198. // data will be transferred to the _pTargetMasterIndex.
  199. //
  200. //----------------------------------------------------------------------------
  201. const LONGLONG eSigMindex = 0x58444e4947524d4di64; // "MMRGINDX"
  202. class CMasterMergeIndex : public CDiskIndex
  203. {
  204. friend class CMPersDeComp;
  205. friend class CResManager;
  206. public:
  207. //
  208. // The target master index MUST exist with both the index
  209. // and directory streams constructed on disk before calling
  210. // this constructor.
  211. //
  212. CMasterMergeIndex(
  213. PStorage & storage,
  214. WORKID widNewMaster,
  215. INDEXID iid,
  216. WORKID widMax,
  217. CPersIndex * pCurrentMaster,
  218. WORKID widMasterLog,
  219. CMMergeLog * pMMergeLog = 0 );
  220. ~CMasterMergeIndex();
  221. void SetMMergeIndSnap( CIndexSnapshot * pIndSnap )
  222. {
  223. Win4Assert( 0 == _pIndSnap && 0 != pIndSnap );
  224. _pIndSnap = pIndSnap;
  225. }
  226. BOOL IsMasterMergeIndex() const { return TRUE; }
  227. void Remove();
  228. void Merge( CIndexSnapshot& indSnap,
  229. const CPartition & partn,
  230. CCiFrmPerfCounter & mergeProgress,
  231. BOOL fGetRW ) {}
  232. void Merge( CWKeyList * pNewKeyList,
  233. CFreshTest * pFresh,
  234. const CPartition & partn,
  235. CCiFrmPerfCounter & mergeProgress,
  236. CCiFrameworkParams & frmwrkParams,
  237. BOOL fGetRW );
  238. CKeyCursor * QueryCursor();
  239. CKeyCursor * QueryKeyCursor(const CKey * pKey);
  240. COccCursor * QueryCursor( const CKey * pkey,
  241. BOOL isRange,
  242. ULONG & cMaxNodes );
  243. COccCursor * QueryRangeCursor( const CKey * pkey,
  244. const CKey * pkeyEnd,
  245. ULONG & cMaxNodes );
  246. COccCursor * QuerySynCursor( CKeyArray & keyArr,
  247. BOOL isRange,
  248. ULONG & cMaxNodes );
  249. unsigned Size () const
  250. { return _ulInitSize; }
  251. WORKID ObjectId() const
  252. { return _pTargetMasterIndex->ObjectId(); }
  253. void AbortMerge()
  254. {
  255. _fAbortMerge = TRUE;
  256. }
  257. void ClearAbortMerge()
  258. {
  259. _fAbortMerge = FALSE;
  260. }
  261. void FillRecord ( CIndexRecord & record );
  262. WORKID MaxWorkId () const
  263. {
  264. Win4Assert( _widMax == _pTargetMasterIndex->MaxWorkId() );
  265. return _pTargetMasterIndex->MaxWorkId();
  266. }
  267. void SetNewKeyList( CWKeyList * pNewKeyList )
  268. {
  269. _pNewKeyList = pNewKeyList;
  270. }
  271. #ifdef KEYLIST_ENABLED
  272. CRWStore * ComputeRelevantWords(ULONG cRows,ULONG cRW,WORKID *pwid,
  273. CKeyList *pkl);
  274. CRWStore * AcquireRelevantWords();
  275. #endif // KEYLIST_ENABLED
  276. CPersIndex * GetCurrentMasterIndex()
  277. {
  278. return _pCurrentMasterIndex;
  279. }
  280. inline void Reference();
  281. inline void Release();
  282. CIndexSnapshot & LokGetIndSnap() { return *_pIndSnap; }
  283. void AcquireCurrentAndTarget( CPersIndex ** ppCurrentMaster,
  284. CPersIndex ** ppTargetMaster );
  285. #ifdef CIEXTMODE
  286. void CiExtDump(void *ciExtSelf);
  287. #endif
  288. private:
  289. PDirectory & GetTargetDir()
  290. {
  291. return( _pTargetMasterIndex->GetDirectory() );
  292. }
  293. void CreateRange( COccCurStack & curStk,
  294. const CKey * pkey,
  295. const CKey * pkeyEnd,
  296. ULONG & cMaxNodes );
  297. void RestoreIndexDirectory( const CKeyBuf & idxSplitKey,
  298. WORKID widMax,
  299. const BitOffset & idxBitOffRestart);
  300. #if KEYLIST_ENABLED
  301. void RestoreKeyListDirectory( const CKeyBuf & idxSplitKey,
  302. WORKID widMax,
  303. CWKeyList * pNewKeyList,
  304. const CKeyBuf & keylstSplitKey );
  305. #endif // KEYLIST_ENABLED
  306. CKeyCursor * StartMasterMerge( CIndexSnapshot & indSnap,
  307. CMMergeLog & mMergeLog,
  308. CWKeyList * pNewKeyList );
  309. void ReloadMasterMerge( CMMergeLog & mMergeLog );
  310. void CleanupMMergeState();
  311. void SetMaxWorkId ( WORKID widMax )
  312. {
  313. Win4Assert( 0 != _pTargetMasterIndex );
  314. CIndex::SetMaxWorkId( widMax );
  315. _pTargetMasterIndex->SetMaxWorkId( widMax );
  316. }
  317. void ReleaseTargetAndCurrent()
  318. {
  319. _pCurrentMasterIndex = 0;
  320. _pTargetMasterIndex = 0;
  321. }
  322. CPersIndex * GetTargetMaster()
  323. {
  324. return( _pTargetMasterIndex );
  325. }
  326. CKeyCursor * QuerySplitCursor(const CKey * pKey);
  327. void ShrinkFromFront( const CKeyBuf & keyBuf );
  328. const LONGLONG _sigMindex; // Signature
  329. CPersIndex * _pCurrentMasterIndex; // Current master index
  330. CPersIndex * _pTargetMasterIndex; // Target master index
  331. CPhysIndex * _pTargetSink; // Target sink to which we
  332. // are adding keys.
  333. WORKID _widMasterLog; // WORKID of new master index
  334. CPersComp * _pCompr; // Compressor for the new index.
  335. CTrackSplitKey * _pTrackIdxSplitKey; // Split key tracker for index.
  336. #ifdef KEYLIST_ENABLED
  337. CTrackSplitKey * _pTrackKeyLstSplitKey; // Split key tracker for KeyList
  338. #endif // KEYLIST_ENABLED
  339. ULONG _ulInitSize; // Initial guess at index size
  340. CSplitKeyInfo _idxSplitKeyInfo; // SplitKey at checkpoint, used
  341. // for queries
  342. CMutexSem _mutex; // Used to control access to
  343. // dirs during master merge
  344. ULONG _ulFirstPageInUse; // First used page in index
  345. CWKeyList * _pNewKeyList; // The new key list being
  346. BOOL _fAbortMerge; // Flag to indicate if merge
  347. // must be aborted.
  348. PStorage & _storage;
  349. CRWStore * _pRWStore;
  350. CIndexSnapshot * _pIndSnap; // Index Snap Shot for the
  351. // merge.
  352. BOOL _fStateLoaded; // Set to TRUE if the master
  353. // merge state is loaded.
  354. };
  355. //+---------------------------------------------------------------------------
  356. //
  357. // Function: Reference
  358. //
  359. // Synopsis: RefCounts the composite index for QUERY so it will not get
  360. // deleted while in use by an in-progress QUERY.
  361. //
  362. // History: 8-30-94 srikants Created
  363. //
  364. // Assumption: We are under RESMAN LOCK
  365. //
  366. // Notes: It is important to ref-count both the current master and
  367. // target master indexes separately in-addition to refcounting
  368. // this index. Ref-Counting the current master prevents the
  369. // merge snapshot from deleting it while the query is going on.
  370. // Ref-counting the target master protects a long-running query
  371. // from a second merge.
  372. // Consider the following sequence. The refcount is enclosed
  373. // in parenthesis.
  374. //
  375. // 1. Merge M1 is in progress and adding keys to target T1(0).
  376. // 2. Query Q1 starts. T1(0)
  377. // 3. M1 completes. T1(0)
  378. // 4. Merge M2 starts and produces target T2. T1(1)
  379. // 5. M2 completes; T1(0) and is zombie.
  380. // The merge snapshot will then delete T1 because it is a
  381. // zombie and refcount is 0.
  382. //
  383. // To prevent in step 5, we must refcount T1 in step 2 so it
  384. // looks like
  385. // 2. Query Q1 starts. T1(1)
  386. // 3. ... T1(1)
  387. // 4. ... T1(1)
  388. // 5. ... T1(1) and is zombie
  389. // Because T1 is still in use, it will not be deleted.
  390. //
  391. //----------------------------------------------------------------------------
  392. inline void CMasterMergeIndex::Reference()
  393. {
  394. CIndex::Reference();
  395. Win4Assert( 0 != _pTargetMasterIndex );
  396. _pTargetMasterIndex->Reference();
  397. if ( _pCurrentMasterIndex )
  398. _pCurrentMasterIndex->Reference();
  399. }
  400. //+---------------------------------------------------------------------------
  401. //
  402. // Function: Release
  403. //
  404. // Synopsis: Releases the composite index.
  405. //
  406. // History: 8-30-94 srikants Created
  407. //
  408. // Notes: We are under RESMAN lock.
  409. //
  410. //----------------------------------------------------------------------------
  411. inline void CMasterMergeIndex::Release()
  412. {
  413. if ( _pCurrentMasterIndex )
  414. _pCurrentMasterIndex->Release();
  415. Win4Assert( 0 != _pTargetMasterIndex );
  416. _pTargetMasterIndex->Release();
  417. CIndex::Release();
  418. }
  419. //+---------------------------------------------------------------------------
  420. //
  421. // Class: SByteArray
  422. //
  423. // Purpose: Smart pointer to a memory block.
  424. //
  425. // History: 9-29-94 srikants Created
  426. //
  427. // Notes:
  428. //
  429. //----------------------------------------------------------------------------
  430. class SByteArray
  431. {
  432. public:
  433. SByteArray( void * p ) : _pb( (BYTE *) p)
  434. {
  435. }
  436. ~SByteArray()
  437. {
  438. delete _pb;
  439. }
  440. void Set( void * p )
  441. {
  442. Win4Assert( 0 == _pb );
  443. _pb = (BYTE *) p;
  444. }
  445. void * Acquire()
  446. {
  447. void * pTemp = _pb;
  448. _pb = 0;
  449. return(pTemp);
  450. }
  451. private:
  452. BYTE * _pb;
  453. };