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.

474 lines
12 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: MCURSOR.CXX
  7. //
  8. // Contents: Merge Cursor
  9. //
  10. // Classes: CMergeCursor
  11. //
  12. // History: 06-May-91 BartoszM Created
  13. //
  14. // widHeap keyHeap
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <pch.cxx>
  18. #pragma hdrstop
  19. #include <curstk.hxx>
  20. #include "mcursor.hxx"
  21. //+---------------------------------------------------------------------------
  22. //
  23. // Member: CMergeCursor::CMergeCursor, public
  24. //
  25. // Synopsis: Create a cursor that merges a number of cursors.
  26. //
  27. // Arguments: [cCursor] -- count of cursors
  28. // [aCursor] -- array of pointers to cursors
  29. //
  30. // History: 06-May-91 BartoszM Created
  31. // 24-Jan-92 AmyA Modified to take CKeyCurArray as a
  32. // parameter.
  33. //
  34. // Notes: The cursors and the array will be deleted by destructor.
  35. // Leaves widHeap empty.
  36. //
  37. //----------------------------------------------------------------------------
  38. CMergeCursor::CMergeCursor( CKeyCurStack & stkCursor )
  39. : _keyHeap (),
  40. _widHeap ( stkCursor.Count() )
  41. {
  42. _widMax = 0; // not valid
  43. // Two step construction of the heap.
  44. // We have to make sure that all cursors have a valid key
  45. int cCursor = stkCursor.Count();
  46. int count = 0;
  47. // remove empty cursors. GetKey() can fail; don't leak cursors.
  48. for ( int i = 0; i < cCursor; i++ )
  49. {
  50. CKeyCursor *pCur = stkCursor.Get( i );
  51. Win4Assert( 0 != pCur );
  52. if ( 0 == pCur->GetKey() )
  53. stkCursor.Free( i );
  54. else
  55. count++;
  56. }
  57. XArray<CKeyCursor *> aCursor( count );
  58. for ( count = 0, i = 0; i < cCursor; i++ )
  59. {
  60. CKeyCursor *pCur = stkCursor.Get( i );
  61. if ( 0 != pCur )
  62. aCursor[ count++ ] = pCur;
  63. }
  64. delete [] stkCursor.AcqStack();
  65. _keyHeap.MakeHeap ( count, aCursor.Acquire() );
  66. if ( !_keyHeap.IsEmpty() )
  67. {
  68. _iid = _keyHeap.Top()->IndexId();
  69. _pid = _keyHeap.Top()->Pid();
  70. }
  71. ciDebugOut(( DEB_ITRACE, "merge cursor has %d cursors\n", count ));
  72. } //CMergeCursor
  73. //+---------------------------------------------------------------------------
  74. //
  75. // Member: CMergeCursor::GetKey, public
  76. //
  77. // Synopsis: Get current key.
  78. //
  79. // History: 06-May-91 BartoszM Created
  80. //
  81. // Notes: Does not replenish widHeap
  82. // Current key is defined as:
  83. // 1. cur key of all cursors in widHeap, or,
  84. // 2. if widHeap empty, cur key of Top of key heap
  85. // (and cur key of all cursors in keyHeap with
  86. // the same cur key).
  87. //
  88. //----------------------------------------------------------------------------
  89. const CKeyBuf * CMergeCursor::GetKey()
  90. {
  91. if ( _widHeap.IsEmpty() )
  92. {
  93. if ( _keyHeap.IsEmpty() )
  94. return 0;
  95. return _keyHeap.Top()->GetKey();
  96. }
  97. return _widHeap.Top()->GetKey();
  98. }
  99. //+---------------------------------------------------------------------------
  100. //
  101. // Member: CMergeCursor::WorkId, public
  102. //
  103. // Synopsis: Get current work id.
  104. //
  105. // History: 06-May-91 BartoszM Created
  106. //
  107. // Notes: Current wid is defined as:
  108. // 1. Cur wid of Top of widHeap (and cur wid of all
  109. // cursors in widHeap with the same wid-- however,
  110. // NextWid should not increment the others, since
  111. // they correspond to different index id's), or,
  112. // 2. if widHeap empty: replenish it
  113. //
  114. //----------------------------------------------------------------------------
  115. WORKID CMergeCursor::WorkId()
  116. {
  117. if ( _widHeap.IsEmpty() && !ReplenishWid() )
  118. return widInvalid;
  119. return _widHeap.Top()->WorkId();
  120. }
  121. //+---------------------------------------------------------------------------
  122. //
  123. // Member: CMergeCursor::Occurrence, public
  124. //
  125. // Synopsis: Get current occurrence.
  126. //
  127. // History: 06-May-91 BartoszM Created
  128. //
  129. // Notes: Current occurrence is defined as:
  130. // 1. cur occ of Top of widHeap, or,
  131. // 2. if widHeap empty, replenish it.
  132. //
  133. //----------------------------------------------------------------------------
  134. OCCURRENCE CMergeCursor::Occurrence()
  135. {
  136. if ( _widHeap.IsEmpty() && !ReplenishWid() )
  137. return OCC_INVALID;
  138. return _widHeap.Top()->Occurrence();
  139. }
  140. //+---------------------------------------------------------------------------
  141. //
  142. // Member: CMergeCursor::GetNextKey, public
  143. //
  144. // Synopsis: Move to next key
  145. //
  146. // Returns: Target key or NULL if no more keys
  147. //
  148. // History: 06-May-91 BartoszM Created
  149. //
  150. // Effects: Updates _iid _pid to the ones of the keyHeap top
  151. //
  152. // Notes: 1. Increment and move to keyHeap all cursors
  153. // from widHeap, or,
  154. // 2. if widHeap empty, increment and reheap all
  155. // cursors in keyHeap with the same cur key
  156. // as the Top.
  157. //
  158. //----------------------------------------------------------------------------
  159. const CKeyBuf * CMergeCursor::GetNextKey()
  160. {
  161. if ( ! _widHeap.IsEmpty() )
  162. {
  163. // move widHeap to keyHeap advancing all cursors
  164. CKeyCursor * cur;
  165. while ( ( cur = _widHeap.RemoveBottom() ) != 0 )
  166. {
  167. if ( cur->GetNextKey() == 0 )
  168. {
  169. delete cur;
  170. }
  171. else
  172. {
  173. _keyHeap.Add ( cur );
  174. }
  175. }
  176. }
  177. else if ( !_keyHeap.IsEmpty() )
  178. {
  179. // widHeap was empty. Advance all cursors
  180. // with the lowest key.
  181. CKeyBuf key = *_keyHeap.Top()->GetKey();
  182. do
  183. {
  184. if ( _keyHeap.Top()->GetNextKey() == 0 )
  185. {
  186. delete _keyHeap.RemoveTop();
  187. if ( _keyHeap.IsEmpty () )
  188. return 0;
  189. }
  190. else
  191. {
  192. _keyHeap.Reheap();
  193. }
  194. } while ( AreEqual(&key, _keyHeap.Top()->GetKey()) );
  195. }
  196. else
  197. return 0;
  198. if ( _keyHeap.IsEmpty() )
  199. return 0;
  200. CKeyCursor* cur = _keyHeap.Top();
  201. _pid = cur->Pid();
  202. _iid = cur->IndexId();
  203. return cur->GetKey();
  204. }
  205. //+---------------------------------------------------------------------------
  206. //
  207. // Member: CMergeCursor::NextWorkId, public
  208. //
  209. // Synopsis: Move to next work id
  210. //
  211. // Returns: Target work id or widInvalid if no more wid's for current key
  212. //
  213. // Effects: Updates _iid to the one of the widHeap top
  214. //
  215. //
  216. // History: 06-May-91 BartoszM Created
  217. //
  218. // Notes: The same work id may be returned multiple times,
  219. // corresponding to multiple indexes.
  220. // 1. Increment Top of widHeap and reheap, or,
  221. // 2. if widHeap empty, replenish it
  222. //
  223. //----------------------------------------------------------------------------
  224. WORKID CMergeCursor::NextWorkId()
  225. {
  226. if ( _widHeap.IsEmpty() && !ReplenishWid() )
  227. return widInvalid;
  228. _widHeap.Top()->NextWorkId();
  229. _widHeap.Reheap();
  230. CKeyCursor* cur = _widHeap.Top();
  231. _iid = cur->IndexId();
  232. return cur->WorkId();
  233. }
  234. //+---------------------------------------------------------------------------
  235. //
  236. // Member: CMergeCursor::NextOccurrence, public
  237. //
  238. // Synopsis: Move to next occurrence
  239. //
  240. // Returns: Target occurrence or OCC_INVALID if no more occurrences
  241. // for current (wid, index id) combination.
  242. //
  243. // History: 06-May-91 BartoszM Created
  244. //
  245. // Notes: 1. Increment Top of widHeap (do not reheap!), or,
  246. // 2. if widHeap empty, replenish it
  247. //
  248. //----------------------------------------------------------------------------
  249. OCCURRENCE CMergeCursor::NextOccurrence()
  250. {
  251. if ( _widHeap.IsEmpty() && !ReplenishWid() )
  252. return OCC_INVALID;
  253. return _widHeap.Top()->NextOccurrence();
  254. }
  255. //+---------------------------------------------------------------------------
  256. //
  257. // Member: CMergeCursor::MaxOccurrence
  258. //
  259. // Synopsis: Returns max occurrence of current wid
  260. //
  261. // History: 20-Jun-96 SitaramR Created
  262. //
  263. //----------------------------------------------------------------------------
  264. OCCURRENCE CMergeCursor::MaxOccurrence()
  265. {
  266. if ( _widHeap.IsEmpty() )
  267. return OCC_INVALID;
  268. return _widHeap.Top()->MaxOccurrence();
  269. }
  270. //+---------------------------------------------------------------------------
  271. //
  272. // Member: CMergeCursor::WorkIdCount, public
  273. //
  274. // Synopsis: return wid count
  275. //
  276. // History: 21-Jun-91 BartoszM Created
  277. //
  278. // Notes: 1. Sum up wid count of all cursors in widHeap, or,
  279. // 2. if widHeap empty, replenish it
  280. //
  281. //----------------------------------------------------------------------------
  282. ULONG CMergeCursor::WorkIdCount()
  283. {
  284. // Sum up all wid counts for the same key.
  285. // move all cursors with the same key to wid heap
  286. if (_widHeap.IsEmpty() && !ReplenishWid())
  287. {
  288. return 0;
  289. }
  290. int count = _widHeap.Count();
  291. ULONG widCount = 0;
  292. CKeyCursor **curVec = _widHeap.GetVector();
  293. while ( --count >= 0 )
  294. widCount += curVec[count]->WorkIdCount();
  295. // ciDebugOut (( DEB_ITRACE, "merge : wid count %ld\n", widCount ));
  296. return widCount;
  297. }
  298. //+---------------------------------------------------------------------------
  299. //
  300. // Member: CMergeCursor::OccurrenceCount, public
  301. //
  302. // Synopsis: return occurrence count
  303. //
  304. // History: 21-Jun-91 BartoszM Created
  305. //
  306. // Notes: 1. Return occ count of Top of widHeap
  307. // Occ counts of other cursors with the
  308. // same wid do not count! They will
  309. // be returned after NextWorkId is called
  310. // 2. if widHeap empty, replenish it
  311. //
  312. //----------------------------------------------------------------------------
  313. ULONG CMergeCursor::OccurrenceCount()
  314. {
  315. if ( _widHeap.IsEmpty() && !ReplenishWid() )
  316. {
  317. return 0;
  318. }
  319. return _widHeap.Top()->OccurrenceCount();
  320. }
  321. //+---------------------------------------------------------------------------
  322. //
  323. // Member: CMergeCursor::HitCount, public
  324. //
  325. // Synopsis: return occurrence count
  326. //
  327. // History: 27-Feb-92 AmyA Created
  328. //
  329. // Notes: see notes for OccurrenceCount().
  330. //
  331. //----------------------------------------------------------------------------
  332. ULONG CMergeCursor::HitCount()
  333. {
  334. return OccurrenceCount();
  335. }
  336. //+---------------------------------------------------------------------------
  337. //
  338. // Member: CMergeCursor::ReplenishWid, protected
  339. //
  340. // Synopsis: Replenish the wid heap
  341. //
  342. // Returns: TRUE if successful, FALSE if key heap exhausted
  343. //
  344. // Effects: Updates _iid to the ones of the widHeap top
  345. //
  346. // History: 06-May-91 BartoszM Created
  347. //
  348. //----------------------------------------------------------------------------
  349. BOOL CMergeCursor::ReplenishWid()
  350. {
  351. if ( _keyHeap.IsEmpty() )
  352. {
  353. return FALSE;
  354. }
  355. // Move all cursors with the lowest key
  356. // to widHeap
  357. CKeyBuf key = *(_keyHeap.Top()->GetKey());
  358. do {
  359. CKeyCursor* cur = _keyHeap.RemoveTop();
  360. _widHeap.Add ( cur );
  361. } while ( !_keyHeap.IsEmpty()
  362. && AreEqual( &key, _keyHeap.Top()->GetKey()) );
  363. _iid = _widHeap.Top()->IndexId();
  364. return TRUE;
  365. }
  366. //
  367. // Remove RefillStream() and FreeStream() once NTFS supports
  368. // sparse file operations on parts of a file when other parts
  369. // of the file are mapped. This won't happen any time soon.
  370. //
  371. void CMergeCursor::FreeStream()
  372. {
  373. ULONG cCursors = _keyHeap.Count();
  374. CKeyCursor **aCursors = _keyHeap.GetVector();
  375. ciDebugOut(( DEB_ITRACE, "free key heap has %d cursors\n", cCursors ));
  376. for ( ULONG i = 0; i < cCursors; i++ )
  377. aCursors[ i ]->FreeStream();
  378. cCursors = _widHeap.Count();
  379. aCursors = _widHeap.GetVector();
  380. ciDebugOut(( DEB_ITRACE, "free wid heap has %d cursors\n", cCursors ));
  381. for ( i = 0; i < cCursors; i++ )
  382. aCursors[ i ]->FreeStream();
  383. } //FreeStream
  384. void CMergeCursor::RefillStream()
  385. {
  386. ULONG cCursors = _keyHeap.Count();
  387. CKeyCursor **aCursors = _keyHeap.GetVector();
  388. ciDebugOut(( DEB_ITRACE, "refill key heap has %d cursors\n", cCursors ));
  389. for ( ULONG i = 0; i < cCursors; i++ )
  390. aCursors[ i ]->RefillStream();
  391. cCursors = _widHeap.Count();
  392. aCursors = _widHeap.GetVector();
  393. ciDebugOut(( DEB_ITRACE, "refill wid heap has %d cursors\n", cCursors ));
  394. for ( i = 0; i < cCursors; i++ )
  395. aCursors[ i ]->RefillStream();
  396. } //FreeStream