Windows NT 4.0 source code leak
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.

491 lines
15 KiB

4 years ago
  1. /*****************************************************************************
  2. * *
  3. * BTFILL.C *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1990. *
  6. * All Rights reserved. *
  7. * *
  8. ******************************************************************************
  9. * *
  10. * Module Intent *
  11. * *
  12. * Functions for creating a btree by adding keys in order. This is faster *
  13. * and the resulting btree is more compact and has adjacent leaf nodes. *
  14. * *
  15. ******************************************************************************
  16. * *
  17. * Testing Notes *
  18. * *
  19. ******************************************************************************
  20. * *
  21. * Current Owner: JohnSc *
  22. * *
  23. ******************************************************************************
  24. * *
  25. * Released by Development: 00/00/00 *
  26. * *
  27. *****************************************************************************/
  28. /*****************************************************************************
  29. *
  30. * Revision History: Created 08/17/90 by JohnSc
  31. *
  32. * 11/12/90 JohnSc RcFillHbt() wasn't setting rcBtreeError to rcSuccess
  33. * 11/29/90 RobertBu #ifdef'ed out routines that are not used under
  34. * windows.
  35. * 02/04/91 Maha changed ints to INT for MAC
  36. *
  37. *****************************************************************************/
  38. #include <windows.h>
  39. #include <orkin.h>
  40. #include "_mvfs.h"
  41. #include "imvfs.h"
  42. #include "btpriv.h"
  43. // _subsystem( btree );
  44. /*****************************************************************************
  45. * *
  46. * Prototypes *
  47. * *
  48. *****************************************************************************/
  49. RC NEAR PASCAL RcGrowCache( QBTHR qbthr );
  50. KEY NEAR PASCAL KeyLeastInSubtree( QBTHR qbthr, BK bk, INT icbLevel );
  51. /***************************************************************************\
  52. *
  53. - Function: RcGrowCache( qbthr )
  54. -
  55. * Purpose: Grow the cache by one level.
  56. *
  57. * ASSUMES
  58. * args IN: qbthr->ghCache - unlocked
  59. * globals IN: rcBtreeError
  60. *
  61. * PROMISES
  62. * returns: rc
  63. * args OUT: qbthr->bth.cLevels - incremented
  64. * qbthr->bth.ghCache - locked
  65. * qbthr->bth.qCache - points to locked ghCache
  66. * globals OUT: rcBtreeError - set to rcOutOfMemory on error
  67. *
  68. * Note: Root is at level 0, leaves at level qbthr->bth.cLevels - 1.
  69. *
  70. \***************************************************************************/
  71. _private RC NEAR PASCAL
  72. RcGrowCache( QBTHR qbthr )
  73. {
  74. GH gh;
  75. QB qb;
  76. INT cbcb = CbCacheBlock( qbthr );
  77. qbthr->bth.cLevels++;
  78. gh = GhAlloc(GMEM_SHARE| 0, (LONG)cbcb * qbthr->bth.cLevels );
  79. if ( gh == NULL )
  80. {
  81. return SetBtreeErrorRc(rcOutOfMemory);
  82. }
  83. qb = QLockGh( gh );
  84. QvCopy( qb + cbcb,
  85. qbthr->qCache,
  86. (LONG)cbcb * ( qbthr->bth.cLevels - 1 ) );
  87. UnlockGh( qbthr->ghCache );
  88. FreeGh( qbthr->ghCache );
  89. qbthr->ghCache = gh;
  90. qbthr->qCache = qb;
  91. return SetBtreeErrorRc(rcSuccess);
  92. }
  93. /***************************************************************************\
  94. *
  95. - Function: KeyLeastInSubtree( qbthr, bk, icbLevel )
  96. -
  97. * Purpose: Return the least key in the subtree speced by bk and
  98. * icbLevel.
  99. *
  100. * ASSUMES
  101. * args IN: qbthr -
  102. * bk - bk at root of subtree
  103. * icbLevel - level of subtree root
  104. *
  105. * PROMISES
  106. * returns: key - the smallest key in the subtree
  107. * args OUT: qbthr->ghCache, ->qCache - contents of cache may change
  108. * globals OUT: rcBtreeError?
  109. *
  110. \***************************************************************************/
  111. _private KEY NEAR PASCAL
  112. KeyLeastInSubtree( QBTHR qbthr, BK bk, INT icbLevel )
  113. {
  114. QCB qcb;
  115. INT icbMost = qbthr->bth.cLevels - 1;
  116. while ( icbLevel < icbMost )
  117. {
  118. qcb = QFromBk( bk, icbLevel, qbthr );
  119. bk = *(BK FAR *)qcb->db.rgbBlock;
  120. ++icbLevel;
  121. }
  122. qcb = QFromBk( bk, icbLevel, qbthr );
  123. return (KEY)qcb->db.rgbBlock + 2 * sizeof( BK );
  124. }
  125. // EXPORTED FUNCTIONS
  126. /***************************************************************************\
  127. *
  128. - Function: HbtInitFill( sz, qbtp )
  129. -
  130. * Purpose: Start the btree fill process. Note that the HBT returned
  131. * is NOT a valid btree handle.
  132. *
  133. * ASSUMES
  134. * args IN: sz - btree name
  135. * qbtp - btree creation parameters
  136. *
  137. * PROMISES
  138. * returns: an HBT that isn't a valid btree handle until RcFiniFillHbt()
  139. * is called on it (with intervening RcFillHbt()'s)
  140. * The only valid operations on this HBT are
  141. * RcFillHbt() - add keys in order one at a time
  142. * RcAbandonHbt() - junk the hbt
  143. * RcFiniFillHbt() - finish adding keys. After this, the
  144. * hbt is a normal btree handle.
  145. * +++
  146. *
  147. * Method: Create a btree. Create a single-block cache.
  148. *
  149. \***************************************************************************/
  150. _public HBT PASCAL
  151. HbtInitFill( LPSTR sz, BTREE_PARAMS FAR *qbtp )
  152. {
  153. HBT hbt;
  154. QBTHR qbthr;
  155. QCB qcb;
  156. RC rc;
  157. // Get a btree handle
  158. hbt = HbtCreateBtreeSz( sz, qbtp );
  159. if ( hbt == NULL ) return NULL;
  160. qbthr = QLockGh( hbt );
  161. assert( qbthr != NULL );
  162. // make a one-block cache
  163. qbthr->ghCache = GhAlloc(GMEM_SHARE| 0, (LONG)CbCacheBlock( qbthr ) );
  164. if ( qbthr->ghCache == NULL )
  165. {
  166. SetBtreeErrorRc(rcOutOfMemory);
  167. goto error_return;
  168. }
  169. qbthr->qCache = QLockGh( qbthr->ghCache );
  170. assert( qbthr->qCache != NULL );
  171. qcb = (QCB)qbthr->qCache;
  172. qbthr->bth.cLevels = 1;
  173. qbthr->bth.bkFirst =
  174. qbthr->bth.bkLast =
  175. qcb->bk = BkAlloc( qbthr );
  176. qcb->bFlags = fCacheDirty | fCacheValid;
  177. qcb->db.cbSlack = qbthr->bth.cbBlock - sizeof( DISK_BLOCK ) + 1
  178. - 2 * sizeof( BK );
  179. qcb->db.cKeys = 0;
  180. SetBkPrev( qcb, bkNil );
  181. UnlockGh( qbthr->ghCache );
  182. UnlockGh( hbt );
  183. return hbt;
  184. error_return:
  185. UnlockGh( hbt );
  186. rc = RcGetBtreeError();
  187. RcAbandonHbt( hbt );
  188. SetBtreeErrorRc(rc);
  189. return NULL;
  190. }
  191. /***************************************************************************\
  192. *
  193. - Function: RcFillHbt( hbt, key, qvRec )
  194. -
  195. * Purpose: Add a key and record (in order) to the "HBT" given.
  196. *
  197. * ASSUMES
  198. * args IN: hbt - NOT a valid hbt: it was produced with HbtInitFill().
  199. * key - key to add. Must be greater than all keys previously
  200. * added.
  201. * qvRec- record associated with key
  202. *
  203. * PROMISES
  204. * returns: error code
  205. * args OUT: hbt - key, record added
  206. * globals OUT: rcBtreeError
  207. * +++
  208. *
  209. * Method: If key and record don't fit in current leaf, allocate a
  210. * new one and make it the current one.
  211. * Add key and record to current block.
  212. *
  213. \***************************************************************************/
  214. _public RC PASCAL
  215. RcFillHbt( HBT hbt, KEY key, QV qvRec )
  216. {
  217. QBTHR qbthr;
  218. QCB qcb;
  219. INT cbRec, cbKey;
  220. QB qb;
  221. assert( hbt != NULL );
  222. qbthr = QLockGh( hbt );
  223. assert( qbthr != NULL );
  224. assert( key != (KEY)NULL );
  225. assert( qvRec != NULL );
  226. qcb = QLockGh( qbthr->ghCache );
  227. assert( qcb != NULL );
  228. cbRec = CbSizeRec( qvRec, qbthr );
  229. cbKey = CbSizeKey( key, qbthr, FALSE );
  230. if ( cbRec + cbKey > qcb->db.cbSlack )
  231. {
  232. RC rc;
  233. // key and rec don't fit in this block: write it out
  234. SetBkNext( qcb, BkAlloc( qbthr ) );
  235. rc = RcWriteBlock( qcb, qbthr );
  236. if ( rc != rcSuccess )
  237. {
  238. UnlockGh( qbthr->ghCache );
  239. FreeGh( qbthr->ghCache );
  240. RcAbandonHf( qbthr->hf );
  241. UnlockGh( hbt );
  242. FreeGh( hbt );
  243. return rc = RcGetBtreeError();
  244. }
  245. // recycle the block
  246. SetBkPrev( qcb, qcb->bk );
  247. qcb->bk = BkNext( qcb );
  248. qcb->bFlags = fCacheDirty | fCacheValid;
  249. qcb->db.cbSlack = qbthr->bth.cbBlock - sizeof( DISK_BLOCK ) + 1
  250. - 2 * sizeof( BK );
  251. qcb->db.cKeys = 0;
  252. }
  253. // add key and rec to the current block;
  254. qb = (QB)&(qcb->db) + qbthr->bth.cbBlock - qcb->db.cbSlack;
  255. QvCopy( qb, (QV)key, (LONG)cbKey );
  256. QvCopy( qb + cbKey, qvRec, (LONG)cbRec );
  257. qcb->db.cKeys++;
  258. qcb->db.cbSlack -= ( cbKey + cbRec );
  259. qbthr->bth.lcEntries++;
  260. UnlockGh( qbthr->ghCache );
  261. UnlockGh( hbt );
  262. return SetBtreeErrorRc(rcSuccess);
  263. }
  264. /***************************************************************************\
  265. *
  266. - Function: RcFiniFillHbt( hbt )
  267. -
  268. * Purpose: Complete filling of the hbt. After this call, the hbt
  269. * is a valid btree handle.
  270. *
  271. * ASSUMES
  272. * args IN: hbt - NOT a valid hbt: created with RcInitFillHbt()
  273. * and filled with keys & records by RcFillHbt().
  274. * globals IN: rcBtreeError
  275. *
  276. * PROMISES
  277. * returns: error code (rcBtreeError)
  278. * args OUT: hbt - a valid hbt (on rcSuccess)
  279. * globals OUT: rcBtreeError
  280. * +++
  281. *
  282. * Method: Take the first key of each leaf block, creating a layer
  283. * of internal nodes.
  284. * Take the first key in each node in this layer to create
  285. * another layer of internal nodes. Repeat until we get
  286. * we get a layer with only one node. That's the root.
  287. *
  288. \***************************************************************************/
  289. _public RC PASCAL
  290. RcFiniFillHbt( HBT hbt )
  291. {
  292. BK bkThisMin, bkThisMost, bkThisCur, // level being scanned
  293. bkTopMin, bkTopMost; // level being created
  294. QBTHR qbthr;
  295. QCB qcbThis, qcbTop;
  296. INT cbKey;
  297. KEY key;
  298. QB qbDst;
  299. RC rc;
  300. assert( hbt != NULL );
  301. qbthr = QLockGh( hbt );
  302. assert( qbthr != NULL );
  303. qbthr->qCache = QLockGh( qbthr->ghCache ); // we know cache is valid
  304. qcbThis = QCacheBlock( qbthr, 0 );
  305. SetBkNext( qcbThis, bkNil );
  306. bkThisMin = qbthr->bth.bkFirst;
  307. bkThisMost = qbthr->bth.bkLast = qcbThis->bk;
  308. if ( bkThisMin == bkThisMost ) // only one leaf
  309. {
  310. qbthr->bth.bkRoot = bkThisMin;
  311. goto normal_return;
  312. }
  313. if ( rcSuccess != RcGrowCache( qbthr ) )
  314. {
  315. goto error_return;
  316. }
  317. qcbTop = QCacheBlock( qbthr, 0 );
  318. qcbTop->bk = bkTopMin = bkTopMost = BkAlloc( qbthr );
  319. qcbTop->bFlags = fCacheDirty | fCacheValid;
  320. qcbTop->db.cbSlack = qbthr->bth.cbBlock - sizeof( DISK_BLOCK ) + 1
  321. - sizeof( BK );
  322. qcbTop->db.cKeys = 0;
  323. // Get first key from each leaf node and build a layer of internal nodes.
  324. // add bk of first leaf to the node
  325. qbDst = qcbTop->db.rgbBlock;
  326. *(BK FAR *)qbDst = bkThisMin;
  327. qbDst += sizeof( BK );
  328. for ( bkThisCur = bkThisMin + 1; bkThisCur <= bkThisMost; ++bkThisCur )
  329. {
  330. qcbThis = QFromBk( bkThisCur, 1, qbthr );
  331. key = (KEY)( qcbThis->db.rgbBlock + 2 * sizeof( BK ) );
  332. cbKey = CbSizeKey( key, qbthr, FALSE );
  333. if ( (INT)(cbKey + sizeof( BK )) > qcbTop->db.cbSlack )
  334. {
  335. // key and bk don't fit in this block: write it out
  336. rc = RcWriteBlock( qcbTop, qbthr );
  337. // recycle the block
  338. qcbTop->bk = bkTopMost = BkAlloc( qbthr );
  339. qcbTop->db.cbSlack = qbthr->bth.cbBlock - sizeof( DISK_BLOCK ) + 1
  340. - sizeof( BK ); // (bk added below)
  341. qcbTop->db.cKeys = 0;
  342. qbDst = qcbTop->db.rgbBlock;
  343. }
  344. else
  345. {
  346. qcbTop->db.cbSlack -= cbKey + sizeof( BK );
  347. QvCopy( qbDst, (QB)key, cbKey );
  348. qbDst += cbKey;
  349. qcbTop->db.cKeys++;
  350. }
  351. *(BK FAR *)qbDst = bkThisCur;
  352. qbDst += sizeof( BK );
  353. }
  354. // Keep adding layers of internal nodes until we have a root.
  355. while ( bkTopMost > bkTopMin )
  356. {
  357. bkThisMin = bkTopMin;
  358. bkThisMost = bkTopMost;
  359. bkTopMin = bkTopMost = BkAlloc( qbthr );
  360. UnlockGh( qbthr->ghCache );
  361. rc = RcGrowCache( qbthr );
  362. qbthr->qCache = QLockGh( qbthr->ghCache );
  363. if ( rc != rcSuccess )
  364. {
  365. goto error_return;
  366. }
  367. qcbTop = QCacheBlock( qbthr, 0 );
  368. qcbTop->bk = bkTopMin;
  369. qcbTop->bFlags = fCacheDirty | fCacheValid;
  370. qcbTop->db.cbSlack = qbthr->bth.cbBlock - sizeof( DISK_BLOCK ) + 1
  371. - sizeof( BK );
  372. qcbTop->db.cKeys = 0;
  373. // add bk of first node of this level to current node of top level;
  374. qbDst = qcbTop->db.rgbBlock;
  375. *(BK FAR *)qbDst = bkThisMin;
  376. qbDst += sizeof( BK );
  377. // for ( each internal node in this level after first )
  378. for ( bkThisCur = bkThisMin + 1; bkThisCur <= bkThisMost; ++bkThisCur )
  379. {
  380. key = KeyLeastInSubtree( qbthr, bkThisCur, 1 );
  381. cbKey = CbSizeKey( key, qbthr, FALSE );
  382. if ( (INT)(cbKey + sizeof( BK )) > qcbTop->db.cbSlack )
  383. {
  384. // key and bk don't fit in this block: write it out
  385. rc = RcWriteBlock( qcbTop, qbthr );
  386. // recycle the block
  387. qcbTop->bk = bkTopMost = BkAlloc( qbthr );
  388. qcbTop->db.cbSlack = qbthr->bth.cbBlock - sizeof( DISK_BLOCK ) + 1
  389. - sizeof( BK ); // (bk added below)
  390. qcbTop->db.cKeys = 0;
  391. qbDst = qcbTop->db.rgbBlock;
  392. }
  393. else
  394. {
  395. qcbTop->db.cbSlack -= cbKey + sizeof( BK );
  396. QvCopy( qbDst, (QB)key, cbKey );
  397. qbDst += cbKey;
  398. qcbTop->db.cKeys++;
  399. }
  400. *(BK FAR *)qbDst = bkThisCur;
  401. qbDst += sizeof( BK );
  402. }
  403. }
  404. assert( bkTopMin == bkTopMost );
  405. qbthr->bth.bkRoot = bkTopMin;
  406. qbthr->bth.bkEOF = bkTopMin + 1;
  407. normal_return:
  408. UnlockGh( qbthr->ghCache );
  409. UnlockGh( hbt );
  410. return RcGetBtreeError();
  411. error_return:
  412. UnlockGh( qbthr->ghCache );
  413. UnlockGh( hbt );
  414. rc = RcGetBtreeError();
  415. RcAbandonHbt( hbt );
  416. return SetBtreeErrorRc(rc);
  417. }
  418. /* EOF */