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.

484 lines
15 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: EntryBuf.Cxx
  7. //
  8. // Contents: Implementation of the CEntryBuffer and associated classes.
  9. //
  10. // Classes: CEntry, CKeyVector, CEntryBuffer, CEntryBufferHandler
  11. //
  12. // History: 18-Mar-93 AmyA Created from wordlist.cxx and
  13. // sort.cxx
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.cxx>
  17. #pragma hdrstop
  18. #include <entrybuf.hxx>
  19. #include <fdaemon.hxx>
  20. #include <pidmap.hxx>
  21. #include <norm.hxx>
  22. // 12 was chosed after some testing on actual data
  23. const unsigned int minPartSize = 12;
  24. // the stack will be big enough to quicksort 2^cwStack entries
  25. const unsigned int cwStack = 32;
  26. //+---------------------------------------------------------------------------
  27. //
  28. // Function: Median, public
  29. //
  30. // Synopsis: Find the median of three entries
  31. //
  32. // Arguments: [apEntry] -- array of pointers to entries
  33. // [i1], [i2], [i3] -- three indexes
  34. //
  35. // History: 07-Jun-91 BartoszM Created
  36. //
  37. //----------------------------------------------------------------------------
  38. unsigned Median ( CEntry * * apEntry,
  39. unsigned i1,
  40. unsigned i2,
  41. unsigned i3 )
  42. {
  43. const CEntry* p1 = apEntry[i1];
  44. const CEntry* p2 = apEntry[i2];
  45. const CEntry* p3 = apEntry[i3];
  46. int c = p1->Compare( p2 );
  47. if ( c > 0 ) // p1 > p2
  48. {
  49. c = p2->Compare( p3 );
  50. if ( c > 0 )
  51. return i2;
  52. else
  53. {
  54. c = p1->Compare( p3 );
  55. return ( c > 0 )? i3: i1;
  56. }
  57. }
  58. else // p2 >= p1
  59. {
  60. c = p1->Compare( p3 );
  61. if ( c > 0 )
  62. return i1;
  63. else
  64. {
  65. c = p2->Compare( p3 );
  66. return ( c > 0 )? i3: i2;
  67. }
  68. }
  69. }
  70. //+---------------------------------------------------------------------------
  71. //
  72. // Function: InsertSort
  73. //
  74. // Synopsis: Last step of sort is to perform a straight insertion sort
  75. // if the limit partition size is > 1.
  76. //
  77. // Arguments: [apEntry] -- array of pointers to sort keys
  78. // [count] -- # of sort keys to be sorted
  79. //
  80. // Notes: First key is at offset 1, last at offset count
  81. //
  82. //---------------------------------------------------------------------------
  83. void InsertSort( CEntry * apEntry[], unsigned count)
  84. {
  85. if (count <= 1) // nothing to sort
  86. return;
  87. // loop from 2 through nth element
  88. for(unsigned j = 2; j <= count; j++)
  89. {
  90. CEntry * key = apEntry[j];
  91. // go backwards from j-1 shifting up keys greater than 'key'
  92. for ( unsigned i = j - 1; i > 0 &&
  93. apEntry[i]->Compare( key ) > 0; i-- )
  94. {
  95. apEntry[i+1] = apEntry[i];
  96. }
  97. // found key less than 'key' or hit the beginning (i == 0)
  98. // insert key in the hole
  99. apEntry[i+1] = key;
  100. }
  101. }
  102. //+---------------------------------------------------------------------------
  103. //
  104. // Class: CIStack
  105. //
  106. // Purpose: A stack of integers
  107. //
  108. // History: 12-Jun-91 BartoszM Created
  109. //
  110. //----------------------------------------------------------------------------
  111. class CIStack
  112. {
  113. public:
  114. CIStack()
  115. { _top = _arr; }
  116. void Push ( unsigned i )
  117. { *_top++ = i; ciAssert(_top-_arr < cwStack); }
  118. unsigned Pop ()
  119. { return *--_top; }
  120. unsigned Top () const
  121. { return *_top; }
  122. BOOL Empty() const
  123. { return _top == _arr; }
  124. private:
  125. unsigned _arr[cwStack];
  126. unsigned * _top;
  127. };
  128. //+---------------------------------------------------------------------------
  129. //
  130. // Member: CEntryBuffer::CEntryBuffer, public
  131. //
  132. // Synopsis: Fills the buffer with two sentinels.
  133. //
  134. // Arguments: [cb] -- size of the buffer
  135. // [buf] -- Pointer to the buffer
  136. //
  137. // History: 28-May-92 KyleP Added single wid detection
  138. // 07-Jun-91 BartoszM Created
  139. // 22-Feb-96 SrikantS Pass in a buffer instead of allocing
  140. // everytime.
  141. //
  142. //----------------------------------------------------------------------------
  143. CEntryBuffer::CEntryBuffer ( ULONG cb, BYTE * buf )
  144. : _buf( buf ), _cb( cb )
  145. {
  146. Win4Assert( 0 != buf );
  147. // save space at the end of the buffer for the vector array offset.
  148. _pWidSingle = (WORKID*)(_buf + cb - sizeof(WORKID) - sizeof(int));
  149. _bufSize = (unsigned)((BYTE*)_pWidSingle - _buf);
  150. ciAssert ( _bufSize > 4*(sizeof(CEntry) + MAXKEYSIZE) );
  151. // This is done once during construction
  152. _curEntry = (CEntry*) _buf;
  153. _keyVec.Init ( _buf, _bufSize );
  154. // insert sentinel keys
  155. // first sort key is minimum key, i.e., 0 length key with 0 pid, 0
  156. // workid and 0 offset
  157. // this key will be added to the end of _keyVec
  158. // just before sorting.
  159. _curEntry->SetPid ( 0 );
  160. _curEntry->SetWid ( widInvalid );
  161. _curEntry->SetOcc ( 0 );
  162. _curEntry->SetCount ( 0 );
  163. _curEntry = _curEntry->Next();
  164. // then the maximum key
  165. // max key has max size filled with 0xff's
  166. ciAssert ( widInvalid == 0xffffffff );
  167. ciAssert ( OCC_INVALID == 0xffffffff );
  168. ciAssert ( pidInvalid == 0xffffffff );
  169. _curEntry->SetPid ( pidInvalid );
  170. _curEntry->SetWid ( widInvalid );
  171. _curEntry->SetOcc ( OCC_INVALID );
  172. _curEntry->SetCount (MAXKEYSIZE );
  173. memset(_curEntry->GetKeyBuf(), MAX_BYTE, MAXKEYSIZE);
  174. Advance();
  175. //
  176. // *_pWidSingle = 0 means we haven't seen a wid yet.
  177. //
  178. *_pWidSingle = 0;
  179. }
  180. //+---------------------------------------------------------------------------
  181. //
  182. // Member: CEntryBuffer::ReInit, public
  183. //
  184. // Synopsis: Discard old data, reuse the sentinels
  185. //
  186. // History: 28-May-92 KyleP Added single wid detection
  187. // 07-Jun-91 BartoszM Created
  188. //
  189. //----------------------------------------------------------------------------
  190. void CEntryBuffer::ReInit()
  191. {
  192. _keyVec.Init ( _buf, _bufSize );
  193. _curEntry = (CEntry*) _buf;
  194. // skip the min key
  195. _curEntry = _curEntry->Next();
  196. // add the max key to the table
  197. Advance();
  198. //
  199. // *_pWidSingle = 0 means we haven't seen a wid yet.
  200. //
  201. *_pWidSingle = 0;
  202. }
  203. //+---------------------------------------------------------------------------
  204. //
  205. // Member: CEntryBuffer::Done, public
  206. //
  207. // Synopsis: Prepare buffer to be transported to kernel by calculating
  208. // offsets and inserting offset to first key at the end of the
  209. // buffer.
  210. //
  211. // History: 30-Jun-93 AmyA Created
  212. //
  213. //----------------------------------------------------------------------------
  214. void CEntryBuffer::Done()
  215. {
  216. _keyVec.CalculateOffsets ( Count() + 2 ); // include sentinels
  217. // the offset to the vector array is put in the space in the buffer that
  218. // has been reserved after the WORKID pointed to by _pWidSingle.
  219. *(int *)((BYTE *)_pWidSingle + sizeof(WORKID)) =
  220. (int)((BYTE *)(_keyVec.GetVector()) - _buf);
  221. }
  222. //+---------------------------------------------------------------------------
  223. //
  224. // Member: CEntryBuffer::AddEntry, public
  225. //
  226. // Synopsis: Add entry to buffer
  227. //
  228. // Arguments: [cb] -- size of key
  229. // [key] -- buffer with key
  230. // [pid] -- property id
  231. // [widFake] -- fake work id
  232. // [occ] -- occurrence
  233. //
  234. // History: 28-May-92 KyleP Added single wid detection
  235. // 07-Jun-91 BartoszM Created
  236. //
  237. //----------------------------------------------------------------------------
  238. void CEntryBuffer::AddEntry (
  239. unsigned cb, const BYTE * key, PROPID pid, WORKID widFake, OCCURRENCE occ)
  240. {
  241. ciAssert( widFake > 0 && widFake <= maxFakeWid );
  242. ciAssert( widFake != widInvalid );
  243. ciAssert( cb > 0 );
  244. _curEntry->SetWid ( widFake );
  245. _curEntry->SetPid ( pid );
  246. _curEntry->SetOcc ( occ );
  247. _curEntry->SetCount ( cb );
  248. memcpy ( _curEntry->GetKeyBuf(), key, cb );
  249. Advance();
  250. if ( *_pWidSingle == 0 )
  251. *_pWidSingle = widFake;
  252. else if ( *_pWidSingle != widFake )
  253. *_pWidSingle = widInvalid;
  254. }
  255. //+---------------------------------------------------------------------------
  256. //
  257. // Member: CEntryBuffer::Sort, private
  258. //
  259. // Synopsis: sorts the array of keys using a quicksort algorithm
  260. //
  261. // Effects: sorts buffer
  262. //
  263. // History: 22-May-91 Brianb Created
  264. // 05-Jun-91 BartoszM Rewrote it
  265. // 02-Jun-92 KyleP Added wid mapping.
  266. //
  267. //----------------------------------------------------------------------------
  268. void CEntryBuffer::Sort()
  269. {
  270. //ciDebugOut (( DEB_ITRACE, "sorting\n" ));
  271. unsigned count = Count();
  272. if (count == 0) // nothing to sort
  273. return;
  274. CEntry ** apEntry = _keyVec.GetVector();
  275. // compute length of pointer array; note low key and high key
  276. // are at positions 0, count+1
  277. // Use qucksort above threshold size
  278. if (count > minPartSize)
  279. {
  280. CIStack stack;
  281. unsigned left = 1;
  282. unsigned right = count;
  283. // outer loop for sorting partitions
  284. while(TRUE)
  285. {
  286. // compute median of left, right, (left+right)/2
  287. ciAssert(right >= left + minPartSize);
  288. unsigned median = Median ( apEntry,
  289. left,
  290. right,
  291. (left+right)/2);
  292. Win4Assert( median >= left && median <= right );
  293. // exchange median with left
  294. CEntry * pivot = apEntry[median];
  295. apEntry [median] = apEntry[left];
  296. apEntry [left] = pivot;
  297. // point i at the pivot, j beyond the end of partition
  298. // and sort in between
  299. unsigned i = left;
  300. unsigned j = right + 1;
  301. // partition chosen, now burn the candle from both ends
  302. while(TRUE)
  303. {
  304. // increment i until key >= pivot
  305. do
  306. i++;
  307. while ( apEntry[i]->Compare( pivot ) < 0);
  308. // decrement j until key <= pivot
  309. do
  310. j--;
  311. while ( apEntry[j]->Compare( pivot ) > 0);
  312. if ( j <= i )
  313. break;
  314. // swap the elements that are out of order
  315. CEntry* tmp = apEntry[i];
  316. apEntry[i] = apEntry[j];
  317. apEntry[j] = tmp;
  318. } // continue burning
  319. // finally, excange the pivot
  320. apEntry[left] = apEntry[j];
  321. apEntry[j] = pivot;
  322. // entries to the left of j are smaller
  323. // than entries to the right of j
  324. unsigned rsize = right - j;
  325. unsigned lsize = j - left;
  326. // Push the larger one on the stack for later sorting
  327. // If any of the partitions is smaller than the
  328. // minimum, skip it and proceed directly with the other one
  329. // if both are too small, pop the stack
  330. if ( rsize > minPartSize ) // right partition big enough
  331. {
  332. if ( lsize >= rsize ) // left even bigger
  333. {
  334. // sort left later
  335. stack.Push ( j - 1 );
  336. stack.Push ( left );
  337. // sort right now
  338. left = j + 1;
  339. }
  340. else if ( lsize > minPartSize ) // left big enough
  341. {
  342. // sort right later
  343. stack.Push ( right );
  344. stack.Push ( j + 1 );
  345. // sort left now
  346. right = j - 1;
  347. }
  348. else // left too small
  349. {
  350. // sort the right partition now
  351. left = j + 1;
  352. }
  353. }
  354. // right partition too small
  355. else if ( lsize > minPartSize ) // but left big enough
  356. {
  357. // sort the left partition now
  358. right = j - 1;
  359. }
  360. else // both are too small
  361. {
  362. if ( stack.Empty() )
  363. break; // we are done!!!
  364. else
  365. {
  366. // sort the next partition
  367. left = stack.Pop();
  368. right = stack.Pop();
  369. }
  370. }
  371. } // keep sorting
  372. } // Unsorted chunks are of the size <= minPartSize
  373. if (minPartSize > 1)
  374. InsertSort( apEntry, count);
  375. #if CIDBG == 1
  376. // check to see that array is really sorted. j=0 is a sentinel.
  377. for (unsigned j = 1; j <= count; j++)
  378. {
  379. Win4Assert( apEntry[j]->Pid() != pidAll );
  380. if ( apEntry[j]->Compare( apEntry[j+1] ) >= 0 )
  381. {
  382. CKeyBuf first( apEntry[j]->Pid(),
  383. apEntry[j]->GetKeyBuf(),
  384. apEntry[j]->Count() );
  385. CKeyBuf second( apEntry[j+1]->Pid(),
  386. apEntry[j+1]->GetKeyBuf(),
  387. apEntry[j+1]->Count() );
  388. ciDebugOut(( DEB_ERROR, "apEntry[%d]='%*ws' (%p) len=0x%x pid=0x%x wid=0x%x occ=0x%x\n",
  389. j,
  390. first.StrLen(),
  391. first.GetStr(),
  392. first.GetStr(),
  393. first.StrLen(),
  394. first.Pid(),
  395. apEntry[j]->Wid(),
  396. apEntry[j]->Occ() ));
  397. ciDebugOut(( DEB_ERROR, "apEntry[%d]='%*ws' (%p) len=0x%x pid=0x%x wid=0x%x occ=0x%x\n",
  398. j+1,
  399. second.StrLen(),
  400. second.GetStr(),
  401. second.GetStr(),
  402. second.StrLen(),
  403. second.Pid(),
  404. apEntry[j+1]->Wid(),
  405. apEntry[j+1]->Occ() ));
  406. Win4Assert( apEntry[j]->Compare( apEntry[j+1] ) != 0 && "Duplicate keys");
  407. Win4Assert( apEntry[j]->Compare( apEntry[j+1] ) < 0 && "Out of order keys");
  408. }
  409. ciAssert( apEntry[j]->Wid() <= maxFakeWid );
  410. }
  411. #endif //CIDBG == 1
  412. }