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.

615 lines
16 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1991 - 2000.
  5. //
  6. // File: PComp.hxx
  7. //
  8. // Contents: Persistent index compressor, and decompressor
  9. //
  10. // Classes: CCoder, CKeyComp, CPersComp
  11. //
  12. // History: 03-Jul-91 KyleP Created
  13. // 05-Nov-91 BartoszM Restructured to use CCoder
  14. // 05-Dec-93 w-PatG Restructured to use CKeyComp
  15. //
  16. // Notes: The CKeyComp class is under development, testing phase.
  17. // Several revisions must be made to increase the amount of
  18. // inheritence, and improve the coding algorithm used by CKeyComp.
  19. //
  20. //----------------------------------------------------------------------------
  21. #pragma once
  22. #include <keycur.hxx>
  23. #include <misc.hxx>
  24. #include <pdir.hxx>
  25. #include "bitstm.hxx"
  26. #define LINK_MAX_BITS (CI_PAGE_SHIFT + 8) // The max. value of "link" of the persistent index
  27. #define LINK_MAX_VALUE ( 1 << LINK_MAX_BITS ) //
  28. const unsigned OccDeltaBits = 7; // Bits to initially store an
  29. // occurrence delta.
  30. class CPageBuffer;
  31. //+---------------------------------------------------------------------------
  32. //
  33. // Class: CCoder
  34. //
  35. // Purpose: Common class for encoding/decoding of compressed data
  36. //
  37. // Interface:
  38. //
  39. // History: 05-Nov-91 BartoszM Created
  40. //
  41. //----------------------------------------------------------------------------
  42. class CCoder
  43. {
  44. public:
  45. CCoder(WORKID widMax);
  46. CCoder(WORKID widMax, const CKeyBuf& keyInit);
  47. CCoder(CCoder& orig);
  48. virtual ~CCoder();
  49. #if DEVL == 1
  50. void Dump();
  51. #endif
  52. #ifdef CIEXTMODE
  53. void CiExtDump(void *ciExtSelf);
  54. #endif
  55. protected:
  56. UINT AverageWidBits ( UINT cWid );
  57. void SetAverageBits ( UINT cWid )
  58. { _cbitAverageWid = AverageWidBits ( cWid ); }
  59. const WORKID _widMaximum; // Maximum workid in current index
  60. CKeyBuf _key;
  61. WORKID _wid;
  62. OCCURRENCE _occ;
  63. UINT _cbitAverageWid; // Log of the average WorkId delta.
  64. };
  65. __forceinline UINT CCoder::AverageWidBits ( UINT cWid )
  66. {
  67. ciAssert ( cWid != 0 );
  68. ciAssert ( _widMaximum / cWid != 0 );
  69. UINT x = Log2(_widMaximum / cWid);
  70. ciAssert ( x <= ULONG_BITS );
  71. ciAssert ( x > 0 );
  72. return x;
  73. }
  74. //+---------------------------------------------------------------------------
  75. //
  76. // Class: CKeyComp (kcomp)
  77. //
  78. // Purpose: Key compressor
  79. //
  80. // Interface: (Under development)
  81. //
  82. // History: 12-Nov-93 w-PatG Created.
  83. //
  84. // Notes: Derived class that lies between base class CCoder and further
  85. // derived class CPersCoder.
  86. //----------------------------------------------------------------------------
  87. const LONGLONG eSigKeyComp = 0x20504d4f4359454bi64; // "KEYCOMP"
  88. class CKeyComp: public CCoder
  89. {
  90. public:
  91. CKeyComp(CPhysIndex& phIndex, WORKID widMax, BOOL fUseLinks = TRUE);
  92. CKeyComp(CPhysIndex& phIndex,
  93. WORKID widMax,
  94. const BitOffset & bitOffRestart,
  95. const BitOffset & bitOffSplitKey,
  96. const CKeyBuf & splitKey,
  97. BOOL fUseLinks = TRUE);
  98. ~CKeyComp();
  99. void PutKey(const CKeyBuf * pkey, BitOffset & bitOffCurKey);
  100. __forceinline void GetOffset( BitOffset & bitOff )
  101. {
  102. _bitStream.GetOffset( bitOff );
  103. }
  104. __forceinline BOOL IsAtSentinel()
  105. {
  106. return _key.IsMaxKey();
  107. }
  108. #if DEVL == 1
  109. void Dump();
  110. #endif
  111. void ZeroToEndOfPage()
  112. {
  113. _bitStream.ZeroToEndOfPage();
  114. }
  115. void InitSignature()
  116. {
  117. _bitStream.InitSignature();
  118. }
  119. void WriteFirstKeyFull() { _fWriteFirstKeyFull = TRUE; }
  120. #ifdef CIEXTMODE
  121. void CiExtDump(void *ciExtSelf);
  122. #endif
  123. void FreeStream()
  124. {
  125. _bitStream.FreeStream();
  126. _bitStreamLink.FreeStream();
  127. }
  128. protected:
  129. void BitCompress(ULONG ul, unsigned cbitAverage);
  130. void IBitCompress(ULONG ul, unsigned cbitAverage, unsigned bitSize);
  131. void PutPSSize ( unsigned cPrefix, unsigned cSuffix );
  132. void PutPid ( PROPID pid );
  133. const LONGLONG _sigKeyComp; //
  134. CPhysIndex & _phIndex; // The Physical Index for the bitstream
  135. CWBitStream _bitStream; // must be created first
  136. BOOL _fUseLinks;
  137. CPBitStream _bitStreamLink;
  138. BitOffset _bitOffCurKey; // These two bitOffsets are used to rewind
  139. BitOffset _bitOffLastKey; // the compressor to the previous key.
  140. BOOL _fWriteFirstKeyFull; // Write first key on each page fully
  141. };
  142. //+---------------------------------------------------------------------------
  143. //
  144. // Class: CKeyDeComp (kdcomp)
  145. //
  146. // Purpose: Persistent key de-compressor
  147. //
  148. // Interface:
  149. //
  150. // History: 09-Jul-91 KyleP Created.
  151. // 22-Nov-93 w-PatG Converted from CPersDeComp
  152. //
  153. // Notes: One of the key requirements for using de-compressors is
  154. // that if an operation fails because the end of page was
  155. // reached, that *same* operation must be the first one
  156. // performed on the following compressor.
  157. //
  158. //----------------------------------------------------------------------------
  159. const LONGLONG eSigKeyDeComp = 0x504d4f434459454bi64; // "KEYDCOMP"
  160. class CKeyDeComp: public CCoder, public CKeyCursor
  161. {
  162. public:
  163. CKeyDeComp( PDirectory& pDir,
  164. INDEXID iid,
  165. CPhysIndex& phIndex,
  166. WORKID widMax,
  167. BOOL fUseLinks = TRUE,
  168. BOOL fUseDir = TRUE );
  169. CKeyDeComp( PDirectory& pDir,
  170. INDEXID iid,
  171. CPhysIndex& phIndex,
  172. BitOffset& posKey,
  173. const CKeyBuf& keyInit,
  174. const CKey* pKey,
  175. WORKID widMax,
  176. BOOL fUseLinks = TRUE,
  177. BOOL fUseDir = TRUE );
  178. CKeyDeComp( CKeyDeComp & decomp );
  179. ~CKeyDeComp();
  180. const CKeyBuf * GetKey();
  181. const CKeyBuf * GetNextKey();
  182. virtual const CKeyBuf * GetNextKey( BitOffset * pBitOff );
  183. virtual const CKeyBuf * GetKey( BitOffset * pBitOff );
  184. PROPID Pid();
  185. void GetOffset( BitOffset & bitOff );
  186. void FreeStream() { _bitStream.FreeStream(); }
  187. void RefillStream() { _bitStream.RefillStream(); }
  188. //
  189. // Unused. Required for inheritance.
  190. //
  191. OCCURRENCE Occurrence();
  192. OCCURRENCE NextOccurrence();
  193. ULONG OccurrenceCount();
  194. OCCURRENCE MaxOccurrence();
  195. WORKID WorkId();
  196. WORKID NextWorkId();
  197. ULONG HitCount();
  198. #if DEVL == 1
  199. void Dump();
  200. #endif
  201. #ifdef CIEXTMODE
  202. void CiExtDump(void *ciExtSelf);
  203. #endif
  204. protected:
  205. const CKeyBuf* SeekKey(const CKey* pKey);
  206. ULONG BitUnCompress(unsigned cbitAverage);
  207. ULONG IBitUnCompress(unsigned cbitAverage, ULONG ulPartial);
  208. void LoadKey();
  209. void LoadPSSize ( unsigned& cPrefix, unsigned& cSuffix );
  210. void LoadPid ();
  211. BOOL IsAtSentinel() const { return _fAtSentinel; }
  212. const LONGLONG _sigKeyDeComp;
  213. CRBitStream _bitStream;
  214. BOOL _fUseLinks;
  215. BitOffset _bitOffNextKey;
  216. PDirectory& _pDir;
  217. BOOL _fUseDir;
  218. BOOL _fAtSentinel; // TRUE if at sentinel (end) key.
  219. CPhysIndex & _physIndex;
  220. #if (CIDBG == 1)
  221. BOOL _fLastKeyFromDir; // TRUE if last key looked up in directory
  222. #else
  223. BOOL _fDummy; // to keep chk/free size the same
  224. #endif
  225. };
  226. //+---------------------------------------------------------------------------
  227. //
  228. // Class: CPersComp (pcomp)
  229. //
  230. // Purpose: Persistent index compressor
  231. //
  232. // Interface:
  233. //
  234. // History: 03-Jul-91 KyleP Created.
  235. // 02-Dec-93 w-PatG Altered to use CKeyComp.
  236. //
  237. //----------------------------------------------------------------------------
  238. const LONGLONG eSigPersComp = 0x504d4f4353524550i64; // "PERSCOMP"
  239. class CPersComp: public CKeyComp
  240. {
  241. public:
  242. CPersComp(CPhysIndex& phIndex, WORKID widMax);
  243. CPersComp(CPhysIndex& phIndex, WORKID widMax,
  244. const BitOffset & bitOffRestart,
  245. const BitOffset & bitoffSplitKey,
  246. const CKeyBuf & splitKey );
  247. ~CPersComp();
  248. void PutKey(const CKeyBuf * pkey,
  249. ULONG cWorkId,
  250. BitOffset & bitOffCurKey);
  251. void PutWorkId(WORKID wid, OCCURRENCE maxOcc, ULONG cOccurrence);
  252. inline void PutOccurrence(OCCURRENCE occ);
  253. #if DEVL == 1
  254. void Dump();
  255. #endif
  256. #ifdef CIEXTMODE
  257. void CiExtDump(void *ciExtSelf);
  258. #endif
  259. void FreeStream()
  260. {
  261. _bitStreamPatch.FreeStream();
  262. CKeyComp::FreeStream();
  263. }
  264. protected:
  265. inline void BackSpace();
  266. void SetCWIDAccuracy();
  267. void PatchWidCount ();
  268. void PutWidCount ( ULONG cWorkId );
  269. void SkipWidCount ();
  270. void PutMaxOccurrence( OCCURRENCE maxOcc );
  271. const LONGLONG _sigPersComp;
  272. unsigned _cWidActual; // Used to decide if the originally
  273. unsigned _cWidProposed; // Original WorkId count. Used to
  274. // allocate space for the count.
  275. CPBitStream _bitStreamPatch; // Used to back patch wid count
  276. // created after main _bitStream
  277. #if DEVL == 1
  278. unsigned _cOccLeft; // ciVerify the specified number of
  279. #endif
  280. };
  281. //+---------------------------------------------------------------------------
  282. //----------------------------------------------------------------------------
  283. inline void CPersComp::BackSpace()
  284. {
  285. _bitStream.Seek(_bitOffCurKey);
  286. if ( _fUseLinks ) _bitStreamLink.Seek(_bitOffLastKey);
  287. ZeroToEndOfPage();
  288. _phIndex.SetUsedPagesCount( _bitOffCurKey.Page() + 1 );
  289. _cWidProposed = _cWidActual;
  290. _key.SetCount( 0 );
  291. }
  292. //+---------------------------------------------------------------------------
  293. //
  294. // Class: CPersDeComp (pdcomp)
  295. //
  296. // Purpose: Persistent index de-compressor
  297. //
  298. // Interface:
  299. //
  300. // History: 09-Jul-91 KyleP Created.
  301. // 02-Dec-93 w-PatG Altered to use CKeyComp.
  302. //
  303. // Notes: One of the key requirements for using de-compressors is
  304. // that if an operation fails because the end of page was
  305. // reached, that *same* operation must be the first one
  306. // performed on the following compressor.
  307. //
  308. //
  309. //----------------------------------------------------------------------------
  310. const LONGLONG eSigPersDeComp = 0x504d434453524550i64; // "PERSDCMP"
  311. class CPersDeComp: public CKeyDeComp
  312. {
  313. public:
  314. CPersDeComp(
  315. PDirectory& pDir,
  316. INDEXID iid,
  317. CPhysIndex& phIndex,
  318. WORKID widMax,
  319. BOOL fUseLinks = TRUE,
  320. BOOL fUseDir = TRUE );
  321. CPersDeComp(
  322. PDirectory& pDir,
  323. INDEXID iid,
  324. CPhysIndex& phIndex,
  325. BitOffset& posKey,
  326. const CKeyBuf& keyInit,
  327. const CKey* pKey,
  328. WORKID widMax,
  329. BOOL fUseLinks = TRUE,
  330. BOOL fUseDir = TRUE);
  331. CPersDeComp(CPersDeComp& orig);
  332. ~CPersDeComp();
  333. const CKeyBuf * GetNextKey();
  334. const CKeyBuf * GetNextKey( BitOffset * pbitOff );
  335. WORKID WorkId();
  336. WORKID NextWorkId();
  337. ULONG WorkIdCount();
  338. OCCURRENCE Occurrence();
  339. OCCURRENCE NextOccurrence();
  340. OCCURRENCE MaxOccurrence() { return _maxOcc; }
  341. ULONG OccurrenceCount();
  342. ULONG HitCount() {
  343. return OccurrenceCount();
  344. }
  345. void RatioFinished ( ULONG& denom, ULONG& num );
  346. #if DEVL == 1
  347. void Dump();
  348. #endif
  349. #ifdef CIEXTMODE
  350. void CiExtDump(void *ciExtSelf);
  351. #endif
  352. private:
  353. void LoadKey();
  354. void FinishKeyLoad();
  355. void LoadWorkId();
  356. void LoadOccurrence();
  357. void LoadFirstOccurrence();
  358. void LoadWidCount ();
  359. void LoadMaxOccurrence();
  360. const LONGLONG _sigPersDeComp;
  361. //
  362. // 'Current' state of the decompressor. These values are always
  363. // valid and are returned by the various Get functions.
  364. //
  365. ULONG _cWid;
  366. ULONG _cOcc;
  367. OCCURRENCE _maxOcc;
  368. //
  369. // 'Transient' state. Helps the decompressor figure out what/where
  370. // its decompressing.
  371. //
  372. BOOL _fcwidAccurate;
  373. ULONG _cWidLeft;
  374. ULONG _cOccLeft;
  375. };
  376. //+---------------------------------------------------------------------------
  377. //
  378. // Member: CPersComp::PutOccurrence, public
  379. //
  380. // Synopsis: Store an occurrence for the current WorkId.
  381. //
  382. // Arguments: [occ] -- The occurrence to store.
  383. //
  384. // Modifies: [occ] is added to the persistent index.
  385. //
  386. // History: 08-Jul-91 KyleP Created.
  387. //
  388. //----------------------------------------------------------------------------
  389. __forceinline void CPersComp::PutOccurrence(OCCURRENCE occ)
  390. {
  391. ciAssert(occ != OCC_INVALID);
  392. ciAssert(occ > _occ);
  393. ciAssert(_cOccLeft > 0);
  394. ciDebugOut (( DEB_PCOMP | DEB_NOCOMPNAME,"%d ", occ ));
  395. BitCompress(occ - _occ, OccDeltaBits);
  396. _occ = occ;
  397. #if CIDBG == 1
  398. _cOccLeft--;
  399. #endif
  400. }
  401. //+---------------------------------------------------------------------------
  402. //
  403. // Member: CKeyComp::BitCompress, private
  404. //
  405. // Synopsis: Compress and store a number.
  406. //
  407. // Arguments: [ul] -- Number to store.
  408. //
  409. // [cbitAverage] -- Minimum number of bits to store.
  410. //
  411. // Algorithm: First, store the bottom cbitAverage bits.
  412. // while there are more bits to store
  413. // store a 1 bit indicating more to follow
  414. // store the next n bits, where n = 2, 3, 4, ...
  415. // store a 0 bit indicating end of sequence
  416. //
  417. // History: 08-Jul-91 KyleP Created.
  418. // 06-Dec-93 w-PatG Moved from CPersComp.
  419. //
  420. //----------------------------------------------------------------------------
  421. __forceinline void CKeyComp::BitCompress(ULONG ul, unsigned cbitAverage)
  422. {
  423. ciAssert(cbitAverage > 0);
  424. ciAssert(cbitAverage <= ULONG_BITS );
  425. unsigned bitSize = Log2(ul);
  426. //
  427. // If bitSize < cbitAverage then rightshift
  428. // to make it cbitAverage and store cbitAverage bits
  429. // plus the signal bit (0 = done, 1 = more)
  430. //
  431. if (bitSize <= cbitAverage)
  432. {
  433. //
  434. // Store cbitAverage bits of ul
  435. // plus a trailing 0 bit for end-of-sequence
  436. // cbitAverage == ULONG_BITS (maximum!) is a special case,
  437. // no trailing bit is used.
  438. if (cbitAverage < ULONG_BITS)
  439. _bitStream.PutBits(ul << 1, cbitAverage + 1);
  440. else
  441. {
  442. ciAssert(cbitAverage == ULONG_BITS);
  443. _bitStream.PutBits(ul, ULONG_BITS);
  444. }
  445. }
  446. else
  447. IBitCompress(ul, cbitAverage, bitSize);
  448. }
  449. __forceinline PROPID CKeyDeComp::Pid()
  450. {
  451. return GetKey()?
  452. _key.Pid():
  453. pidInvalid;
  454. }