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.

343 lines
8.8 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: ANDCUR.CXX
  7. //
  8. // Contents: And Cursor. Computes intersection of multiple cursors.
  9. //
  10. // Classes: CAndCursor
  11. //
  12. // History: 24-May-91 BartoszM Created.
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include "andcur.hxx"
  18. #pragma optimize( "t", on )
  19. //+---------------------------------------------------------------------------
  20. //
  21. // Member: CAndCursor::CAndCursor, public
  22. //
  23. // Synopsis: Create a cursor that merges a number of cursors.
  24. //
  25. // Arguments: [cCursor] -- count of cursors
  26. // [curStack] -- cursors to merge
  27. //
  28. // Notes: All cursors must come from the same index
  29. // and the same property
  30. //
  31. // History: 24-May-91 BartoszM Created
  32. // 22-Feb-93 KyleP Avoid divide-by-zero
  33. //
  34. //----------------------------------------------------------------------------
  35. CAndCursor::CAndCursor( unsigned cCursor, CCurStack& curStack )
  36. : _aCur ( curStack.AcqStack() ),
  37. _cCur ( cCursor ),
  38. _iCur ( 0 ),
  39. _lMaxWeight( 0 )
  40. {
  41. Win4Assert ( _aCur[0] != 0 );
  42. _iid = _aCur[0]->IndexId();
  43. _pid = _aCur[0]->Pid();
  44. //
  45. // Calculate maximum weight of any child.
  46. //
  47. for ( UINT i = 0; i < _cCur; i++ )
  48. {
  49. _lMaxWeight = max( _lMaxWeight, _aCur[i]->GetWeight() );
  50. }
  51. //
  52. // Avoid divide-by-zero
  53. //
  54. if ( _lMaxWeight == 0 )
  55. _lMaxWeight = 1;
  56. // NTRAID#DB-NTBUG9-84004-2000/07/31-dlee Indexing Service internal cursors aren't optimized to use shortest cursors first
  57. _wid = _aCur[0]->WorkId();
  58. FindConjunction();
  59. }
  60. //+---------------------------------------------------------------------------
  61. //
  62. // Member: CAndCursor::~CAndCursor, public
  63. //
  64. // Synopsis: Delete the cursor together with children
  65. //
  66. // History: 24-May-91 BartoszM Created
  67. //
  68. //----------------------------------------------------------------------------
  69. CAndCursor::~CAndCursor( )
  70. {
  71. for ( unsigned i = 0; i < _cCur; i++ )
  72. delete _aCur[i];
  73. delete (void*) _aCur;
  74. }
  75. //+---------------------------------------------------------------------------
  76. //
  77. // Member: CAndCursor::WorkId, public
  78. //
  79. // Synopsis: Get current work id.
  80. //
  81. // History: 24-May-91 BartoszM Created
  82. //
  83. //----------------------------------------------------------------------------
  84. WORKID CAndCursor::WorkId()
  85. {
  86. return _wid;
  87. }
  88. //+---------------------------------------------------------------------------
  89. //
  90. // Member: CAndCursor::NexWorkID, public
  91. //
  92. // Synopsis: Move to next work id
  93. //
  94. // Returns: Target work id or widInvalid if no more wid's for current key
  95. //
  96. // History: 24-May-91 BartoszM Created
  97. //
  98. //----------------------------------------------------------------------------
  99. WORKID CAndCursor::NextWorkId()
  100. {
  101. // NTRAID#DB-NTBUG9-84004-2000/07/31-dlee Indexing Service internal cursors aren't optimized to use shortest cursors first
  102. _wid = _aCur[0]->NextWorkId();
  103. FindConjunction();
  104. return _wid;
  105. }
  106. //+---------------------------------------------------------------------------
  107. //
  108. // Member: CAndCursor::HitCount, public
  109. //
  110. // Synopsis: Returns smallest HitCount of all keys in current wid.
  111. //
  112. // Requires: _wid set to any of the current wid's
  113. //
  114. // Returns: smallest occurrence count of all keys in wid.
  115. //
  116. // History: 28-Feb-92 AmyA Created
  117. //
  118. // Notes: If there is no conjunction in current wid, returns 0.
  119. //
  120. //----------------------------------------------------------------------------
  121. ULONG CAndCursor::HitCount()
  122. {
  123. ULONG count = _aCur[0]->HitCount();
  124. for ( unsigned i = 1; i < _cCur; i++ )
  125. {
  126. ULONG newcount = _aCur[i]->HitCount();
  127. if ( newcount < count )
  128. count = newcount;
  129. }
  130. return count;
  131. }
  132. void CAndCursor::RatioFinished (ULONG& denom, ULONG& num)
  133. {
  134. denom = 1;
  135. num = 0;
  136. for (unsigned i=0; i < _cCur; i++)
  137. {
  138. ULONG d, n;
  139. _aCur[i]->RatioFinished(d, n);
  140. if (d == n)
  141. {
  142. // done if any cursor is done.
  143. denom = d;
  144. num = n;
  145. Win4Assert( denom > 0 );
  146. break;
  147. }
  148. else if (d > denom)
  149. {
  150. // the one with largest denom
  151. // is the most meaningful
  152. denom = d;
  153. num = n;
  154. }
  155. else if (d == denom && n < num )
  156. {
  157. num = n; // be pessimistic
  158. }
  159. }
  160. }
  161. //+---------------------------------------------------------------------------
  162. //
  163. // Member: CAndCursor::Rank, public
  164. //
  165. // Synopsis: Returns smallest rank of all keys in current wid.
  166. //
  167. // Requires: _wid set to any of the current wid's
  168. //
  169. // Returns: smallest rank of all keys in wid.
  170. //
  171. // History: 14-Apr-92 AmyA Created
  172. // 27-Jul-92 KyleP Use min function for weight
  173. //
  174. // Notes: If there is no conjunction in current wid, returns 0.
  175. //
  176. // See "Automatic Text Processing", G. Salton, 10.4.2 for
  177. // a discussion of the weight formula.
  178. //
  179. //----------------------------------------------------------------------------
  180. LONG CAndCursor::Rank()
  181. {
  182. LONG lRank = (MAX_QUERY_RANK - _aCur[0]->Rank()) * _aCur[0]->GetWeight();
  183. for ( UINT i = 1; i < _cCur; i++ )
  184. {
  185. LONG lNew = (MAX_QUERY_RANK - _aCur[i]->Rank()) * _aCur[i]->GetWeight();
  186. lRank = max( lRank, lNew );
  187. }
  188. //
  189. // Normalize weight.
  190. //
  191. lRank = MAX_QUERY_RANK - (lRank / _lMaxWeight);
  192. return( lRank );
  193. }
  194. //+---------------------------------------------------------------------------
  195. //
  196. // Member: CAndCursor::FindConjunction, private
  197. //
  198. // Synopsis: Find nearest conjunction of all the same work id's
  199. //
  200. // Requires: _wid set to any of the current wid's
  201. //
  202. // Returns: TRUE when found, FALSE otherwise
  203. //
  204. // Modifies: [_wid] to point to conjunction or to widInvalid
  205. //
  206. // History: 24-May-91 BartoszM Created
  207. //
  208. // Notes: If cursors are in conjunction, no change results
  209. //
  210. //----------------------------------------------------------------------------
  211. BOOL CAndCursor::FindConjunction()
  212. {
  213. BOOL fChange;
  214. do
  215. {
  216. fChange = FALSE;
  217. // NTRAID#DB-NTBUG9-84004-2000/07/31-dlee Indexing Service internal cursors aren't optimized to use shortest cursors first
  218. // for all cursors in turn
  219. for ( unsigned i = 0; i < _cCur; i++ )
  220. {
  221. // Seek _wid increment cursor to or past current _wid
  222. // or exit when exhausted
  223. WORKID widTmp = _aCur[i]->WorkId();
  224. while ( widTmp < _wid )
  225. {
  226. widTmp = _aCur[i]->NextWorkId();
  227. if ( widInvalid == widTmp )
  228. {
  229. _wid = widInvalid;
  230. return FALSE;
  231. }
  232. }
  233. // if overshot, try again with new _wid
  234. if ( widTmp > _wid )
  235. {
  236. _wid = widTmp;
  237. fChange = TRUE;
  238. break;
  239. }
  240. }
  241. } while ( fChange );
  242. return TRUE;
  243. }
  244. //+---------------------------------------------------------------------------
  245. //
  246. // Member: CAndCursor::Hit, public
  247. //
  248. // Synopsis: Hits current child (indexed by _iCur)
  249. //
  250. // History: 07-Sep-92 MikeHew Created
  251. //
  252. // Notes: Hit() should not be called more than once, except by
  253. // NextHit()
  254. //
  255. //----------------------------------------------------------------------------
  256. LONG CAndCursor::Hit()
  257. {
  258. Win4Assert( _iCur < _cCur );
  259. if ( WorkId() == widInvalid )
  260. {
  261. return rankInvalid;
  262. }
  263. else
  264. {
  265. return _aCur[_iCur]->Hit();
  266. }
  267. }
  268. //+---------------------------------------------------------------------------
  269. //
  270. // Member: CAndCursor::NextHit, public
  271. //
  272. // Synopsis: NextHits current child (indexed by _iCur)
  273. // If current child becomes empty, increments _iCur
  274. //
  275. // History: 07-Sep-92 MikeHew Created
  276. //
  277. // Notes: NextHit() should not be called after returning rankInvalid
  278. //
  279. //----------------------------------------------------------------------------
  280. LONG CAndCursor::NextHit()
  281. {
  282. Win4Assert( _iCur < _cCur );
  283. LONG rank = _aCur[_iCur]->NextHit();
  284. if ( rank == rankInvalid )
  285. {
  286. if ( ++_iCur < _cCur )
  287. {
  288. return Hit();
  289. }
  290. }
  291. return rank;
  292. }