Leaked source code of windows server 2003
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.

535 lines
14 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: SYNCUR.CXX
  7. //
  8. // Contents: Merge Cursor for multiple keys
  9. //
  10. // Classes: CSynCursor
  11. //
  12. // History: 20-Jan-92 BartoszM and AmyA Created
  13. //
  14. //
  15. // widHeap occHeap
  16. // (same wid)
  17. //
  18. //----------------------------------------------------------------------------
  19. #include <pch.cxx>
  20. #pragma hdrstop
  21. #include <misc.hxx>
  22. #include <curstk.hxx>
  23. #include "syncur.hxx"
  24. #pragma optimize( "t", on )
  25. //+---------------------------------------------------------------------------
  26. //
  27. // Member: CSynCursor::CSynCursor, public
  28. //
  29. // Synopsis: Create a cursor that merges a number of cursors.
  30. //
  31. // Arguments: [curStack] -- cursors to be merged
  32. // [widMax] -- the maximum WORKID of the cursors
  33. //
  34. // History: 20-Jan-92 BartoszM and AmyA Created
  35. //
  36. // Notes: The cursors and the array will be deleted by destructor.
  37. // Leaves occHeap empty.
  38. //
  39. //----------------------------------------------------------------------------
  40. CSynCursor::CSynCursor( COccCurStack &curStack, WORKID widMax )
  41. : COccCursor(widMax), _widHeap (), _occHeap ( curStack.Count() )
  42. {
  43. // Two step construction of the heap.
  44. // We have to make sure that all cursors have a valid key
  45. int cCursor = curStack.Count();
  46. COccCursor **aCursor = curStack.AcqStack();
  47. int count = 0;
  48. // remove empty cursors
  49. for ( int i = 0; i < cCursor; i++ )
  50. {
  51. Win4Assert ( aCursor[i] != 0 );
  52. if ( aCursor[i]->IsEmpty() || aCursor[i]->WorkId() == widInvalid )
  53. {
  54. delete aCursor[i];
  55. }
  56. else if ( count != i )
  57. aCursor[count++] = aCursor[i];
  58. else
  59. count++;
  60. }
  61. _widHeap.MakeHeap ( count, aCursor );
  62. if ( !_widHeap.IsEmpty() )
  63. {
  64. _iid = _widHeap.Top()->IndexId();
  65. _pid = _widHeap.Top()->Pid();
  66. ReplenishOcc();
  67. }
  68. }
  69. //+---------------------------------------------------------------------------
  70. //
  71. // Member: CSynCursor::WorkId, public
  72. //
  73. // Synopsis: Get current work id.
  74. //
  75. // History: 20-Jan-92 BartoszM and AmyA Created
  76. //
  77. // Notes: Current wid is defined as:
  78. // 1. Cur wid of Top of occHeap (and cur wid of all
  79. // cursors in occHeap
  80. // 2. if occHeap empty: cur wid from top of widHeap
  81. //
  82. //----------------------------------------------------------------------------
  83. WORKID CSynCursor::WorkId()
  84. {
  85. if ( _occHeap.IsEmpty() )
  86. {
  87. if (_widHeap.IsEmpty())
  88. {
  89. _pid = pidInvalid;
  90. return widInvalid;
  91. }
  92. else
  93. {
  94. _pid = _widHeap.Top()->Pid();
  95. return _widHeap.Top()->WorkId();
  96. }
  97. }
  98. _pid = _occHeap.Top()->Pid();
  99. return _occHeap.Top()->WorkId();
  100. }
  101. //+---------------------------------------------------------------------------
  102. //
  103. // Member: CSynCursor::Occurrence, public
  104. //
  105. // Synopsis: Get current occurrence.
  106. //
  107. // History: 20-Jan-92 BartoszM and AmyA Created
  108. //
  109. // Notes: Current occurrence is defined as:
  110. // 1. cur occ of top of occHeap and cur occ of all other
  111. // cursors in it with the same cur occ
  112. //
  113. //----------------------------------------------------------------------------
  114. OCCURRENCE CSynCursor::Occurrence()
  115. {
  116. if ( _occHeap.IsEmpty() )
  117. return OCC_INVALID;
  118. return _occHeap.Top()->Occurrence();
  119. }
  120. //+---------------------------------------------------------------------------
  121. //
  122. // Member: CSynCursor::NextWorkId, public
  123. //
  124. // Synopsis: Move to next work id
  125. //
  126. // Returns: Target work id or widInvalid if no more wid's
  127. //
  128. // Effects: Updates _iid to the one of the widHeap top
  129. //
  130. //
  131. // History: 20-Jan-92 BartoszM and AmyA Created
  132. //
  133. // Notes: 1. increment and move to widHeap all cursors in occHeap, or,
  134. // 2. if occHeap empty, increment and reheap all cursors with
  135. // the same wid as Top of widHeap, or,
  136. // 3. if widHeap empty, return widInvalid.
  137. //
  138. //----------------------------------------------------------------------------
  139. WORKID CSynCursor::NextWorkId()
  140. {
  141. if ( ! _occHeap.IsEmpty() )
  142. {
  143. COccCursor * cur;
  144. while ( ( cur = _occHeap.RemoveBottom() ) != 0 )
  145. {
  146. WORKID wid = cur->NextWorkId();
  147. _widHeap.AddKey( cur, wid );
  148. }
  149. }
  150. else
  151. {
  152. if ( _widHeap.IsEmpty() )
  153. return widInvalid;
  154. WORKID wid = _widHeap.Top()->WorkId();
  155. if ( wid == widInvalid )
  156. return widInvalid;
  157. do
  158. {
  159. _widHeap.Top()->NextWorkId();
  160. _widHeap.ReheapKey();
  161. } while ( _widHeap.Top()->WorkId() == wid && wid != widInvalid );
  162. }
  163. if ( WorkId() != widInvalid )
  164. ReplenishOcc();
  165. return WorkId();
  166. }
  167. //+---------------------------------------------------------------------------
  168. //
  169. // Member: CSynCursor::NextOccurrence, public
  170. //
  171. // Synopsis: Move to next occurrence
  172. //
  173. // Returns: Target occurrence or OCC_INVALID if no more occurrences
  174. // for current (wid, index id) combination.
  175. //
  176. // History: 20-Jan-92 BartoszM and AmyA Created
  177. //
  178. // Notes: 1. Increment and reheap Top of occHeap
  179. //
  180. //----------------------------------------------------------------------------
  181. OCCURRENCE CSynCursor::NextOccurrence()
  182. {
  183. if ( _occHeap.IsEmpty() )
  184. return OCC_INVALID;
  185. OCCURRENCE occPrev = _occHeap.Top()->Occurrence();
  186. if ( occPrev == OCC_INVALID )
  187. return OCC_INVALID;
  188. // Get the next occurrence. Don't skip duplicate occurrences
  189. // because the pids will be different.
  190. _occHeap.Top()->NextOccurrence();
  191. _occHeap.ReheapKey();
  192. OCCURRENCE occNext = _occHeap.Top()->Occurrence();
  193. // Retrieve the current PID
  194. if ( _occHeap.IsEmpty() )
  195. {
  196. if ( _widHeap.IsEmpty() )
  197. _pid = pidInvalid;
  198. else
  199. _pid = _widHeap.Top()->Pid();
  200. }
  201. else
  202. _pid = _occHeap.Top()->Pid();
  203. return occNext;
  204. } //NextOccurrence
  205. //+---------------------------------------------------------------------------
  206. //
  207. // Member: CSynCursor::WorkIdCount, public
  208. //
  209. // Synopsis: return wid count
  210. //
  211. // History: 20-Jan-92 BartoszM and AmyA Created
  212. //
  213. // Notes: Sum up all wid counts of all cursors in occHeap
  214. // and widHeap.
  215. //
  216. //----------------------------------------------------------------------------
  217. ULONG CSynCursor::WorkIdCount()
  218. {
  219. if ( _occHeap.IsEmpty() && _widHeap.IsEmpty() )
  220. {
  221. return 0;
  222. }
  223. // at least one of heaps is not empty
  224. ULONG widCount = 0;
  225. COccCursor **curVec;
  226. int count = _occHeap.Count();
  227. if ( count > 0 )
  228. {
  229. curVec = _occHeap.GetVector();
  230. while ( --count >= 0 )
  231. widCount += curVec[count]->WorkIdCount();
  232. }
  233. count = _widHeap.Count();
  234. if ( count > 0 )
  235. {
  236. curVec = _widHeap.GetVector();
  237. while ( --count >= 0 )
  238. widCount += curVec[count]->WorkIdCount();
  239. }
  240. return widCount;
  241. }
  242. //+---------------------------------------------------------------------------
  243. //
  244. // Member: CSynCursor::OccurrenceCount, public
  245. //
  246. // Synopsis: return occurrence count
  247. //
  248. // History: 20-Jan-92 BartoszM and AmyA Created
  249. //
  250. // Notes: 1. sum up occ count of all cursors in the occHeap
  251. //
  252. //----------------------------------------------------------------------------
  253. ULONG CSynCursor::OccurrenceCount()
  254. {
  255. // sum up all occ counts for the same wid
  256. if ( _occHeap.IsEmpty() )
  257. return 0;
  258. int count = _occHeap.Count();
  259. ULONG occCount = 0;
  260. COccCursor **curVec = _occHeap.GetVector();
  261. while ( --count >= 0 )
  262. occCount += curVec[count]->OccurrenceCount();
  263. return occCount;
  264. }
  265. //+---------------------------------------------------------------------------
  266. //
  267. // Member: CSynCursor::MaxOccurrence
  268. //
  269. // Synopsis: Returns max occurrence of current wid
  270. //
  271. // History: 26-Jun-96 SitaramR Created
  272. //
  273. //----------------------------------------------------------------------------
  274. OCCURRENCE CSynCursor::MaxOccurrence()
  275. {
  276. Win4Assert( !_occHeap.IsEmpty() );
  277. if ( _occHeap.IsEmpty() )
  278. return OCC_INVALID;
  279. else
  280. return _occHeap.Top()->MaxOccurrence();
  281. }
  282. //+---------------------------------------------------------------------------
  283. //
  284. // Member: CSynCursor::HitCount, public
  285. //
  286. // Synopsis: return occurrence count
  287. //
  288. // History: 28-Feb-92 AmyA Created
  289. //
  290. // Notes: see notes for OccurrenceCount.
  291. //
  292. //----------------------------------------------------------------------------
  293. ULONG CSynCursor::HitCount()
  294. {
  295. return OccurrenceCount();
  296. }
  297. //+---------------------------------------------------------------------------
  298. //
  299. // Member: CSynCursor::Hit, public
  300. //
  301. // Synopsis: Hits the top level child
  302. //
  303. // History: 13-Oct-92 BartoszM Created
  304. //
  305. //----------------------------------------------------------------------------
  306. LONG CSynCursor::Hit()
  307. {
  308. if ( _occHeap.IsEmpty() )
  309. {
  310. return rankInvalid;
  311. }
  312. return _occHeap.Top()->Hit();
  313. }
  314. //+---------------------------------------------------------------------------
  315. //
  316. // Member: CSynCursor::Hit, public
  317. //
  318. // Synopsis: Goes to next occurrence and hits the top level child
  319. //
  320. // History: 13-Oct-92 BartoszM Created
  321. //
  322. //----------------------------------------------------------------------------
  323. LONG CSynCursor::NextHit()
  324. {
  325. if (NextOccurrence() == OCC_INVALID)
  326. return(rankInvalid);
  327. return Hit();
  328. }
  329. //+---------------------------------------------------------------------------
  330. //
  331. // Member: CSynCursor::Rank, public
  332. //
  333. // Synopsis: Returns weighted average of ranks of children
  334. //
  335. // History: 22-Jul-92 BartoszM Created
  336. //
  337. //----------------------------------------------------------------------------
  338. LONG CSynCursor::Rank()
  339. {
  340. if ( _occHeap.IsEmpty() )
  341. {
  342. return 0;
  343. }
  344. unsigned count = _occHeap.Count();
  345. COccCursor **curVec = _occHeap.GetVector();
  346. // One occurance, no need to average
  347. if ( 1 == count )
  348. return curVec[0]->Rank();
  349. ULONG occCount = 0;
  350. LONG rank = 0;
  351. unsigned cWid = 0;
  352. for (unsigned n = 0; n < count; n++)
  353. {
  354. LONG r = curVec[n]->OccurrenceCount() * curVec[n]->GetWeight();
  355. if(r > rank)
  356. rank = r;
  357. cWid += curVec[n]->WorkIdCount();
  358. }
  359. rank /= MAX_QUERY_RANK;
  360. Win4Assert ( cWid != 0 );
  361. rank *= RANK_MULTIPLIER * Log2 ( _widMax / cWid );
  362. OCCURRENCE maxOcc = _occHeap.Top()->MaxOccurrence();
  363. Win4Assert( maxOcc != 0 );
  364. rank /= maxOcc;
  365. return (rank > MAX_QUERY_RANK)? MAX_QUERY_RANK: rank;
  366. }
  367. //+---------------------------------------------------------------------------
  368. //
  369. // Member: CSynCursor::RatioFinished, public
  370. //
  371. // Synopsis: return approximate ratio of documents processed to total
  372. // documents.
  373. //
  374. // Notes: The ratio, while approximate, should not return 1/1 until
  375. // all cursors are exhausted.
  376. //
  377. //----------------------------------------------------------------------------
  378. void CSynCursor::RatioFinished (ULONG& denom, ULONG& num)
  379. {
  380. WORKID widTop = WorkId();
  381. if (widTop == widInvalid)
  382. {
  383. num = denom = 1;
  384. return;
  385. }
  386. denom = 0;
  387. num = 0;
  388. // at least one of the heaps is not empty
  389. COccCursor **vector;
  390. int count = _occHeap.Count();
  391. vector = _occHeap.GetVector();
  392. unsigned cValid = 1;
  393. for (int i = 0; i < count; i++)
  394. {
  395. ULONG d, n;
  396. vector[i]->RatioFinished(d, n);
  397. denom += d;
  398. num += n;
  399. Win4Assert(denom >= d);
  400. if (n == d)
  401. {
  402. WORKID widCurrent = vector[i]->WorkId();
  403. if (widCurrent != widInvalid && widCurrent != widTop)
  404. cValid++;
  405. }
  406. }
  407. count = _widHeap.Count();
  408. vector = _widHeap.GetVector();
  409. for (i = 0; i < count; i++)
  410. {
  411. ULONG d, n;
  412. vector[i]->RatioFinished(d, n);
  413. denom += d;
  414. num += n;
  415. Win4Assert(denom >= d);
  416. if (n == d)
  417. {
  418. WORKID widCurrent = vector[i]->WorkId();
  419. if (widCurrent != widInvalid && widCurrent != widTop)
  420. cValid++;
  421. }
  422. }
  423. Win4Assert( denom > 0 );
  424. if (num == denom && cValid > 1)
  425. denom++;
  426. }
  427. //+---------------------------------------------------------------------------
  428. //
  429. // Member: CSynCursor::ReplenishOcc, private
  430. //
  431. // Synopsis: Replenish the occurrence heap
  432. //
  433. // Returns: TRUE if successful, FALSE if wid heap exhausted
  434. //
  435. // Requires: _occHeap empty
  436. //
  437. // History: 20-Jan-92 BartoszM and AmyA Created
  438. //
  439. //----------------------------------------------------------------------------
  440. BOOL CSynCursor::ReplenishOcc()
  441. {
  442. Win4Assert ( _occHeap.IsEmpty() );
  443. Win4Assert( WorkId() != widInvalid );
  444. if ( _widHeap.IsEmpty() )
  445. return FALSE;
  446. // Move all cursors with the current wid
  447. // to occ heap
  448. WORKID wid = _widHeap.Top()->WorkId();
  449. do
  450. {
  451. COccCursor* cur = _widHeap.RemoveTopKey();
  452. _occHeap.AddKey( cur, cur->Occurrence() );
  453. } while ( !_widHeap.IsEmpty() && (wid == _widHeap.Top()->WorkId()) );
  454. return TRUE;
  455. } //ReplenishOcc