Source code of Windows XP (NT5)
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.

284 lines
7.2 KiB

  1. /*****************************************************************************
  2. * *
  3. * BTDELETE.C *
  4. * *
  5. * Copyright (C) Microsoft Corporation 1989 - 1994. *
  6. * All Rights reserved. *
  7. * *
  8. ******************************************************************************
  9. * *
  10. * Module Intent *
  11. * *
  12. * Btree deletion functions and helpers. *
  13. * *
  14. ******************************************************************************
  15. * *
  16. * Current Owner: Binhn *
  17. * *
  18. *****************************************************************************/
  19. static char s_aszModule[]= __FILE__; /* For error report */
  20. #include <mvopsys.h>
  21. #include <misc.h>
  22. #include <orkin.h>
  23. #include <iterror.h>
  24. #include <wrapstor.h>
  25. #include <_mvutil.h>
  26. /* Put all functions into the same segment to avoid memory fragmentation
  27. * and load time surplus for the MAC
  28. */
  29. // #pragma code_seg ("MVFS")
  30. /***************************************************************************
  31. *
  32. * Public Functions
  33. *
  34. ***************************************************************************/
  35. /***************************************************************************\
  36. *
  37. * @doc PUBLIC API
  38. *
  39. * @func HRESULT PASCAL FAR | RcDeleteHbt |
  40. * delete a key from a btree.
  41. * Just copy over the key and update cbSlack.
  42. * Doesn't yet merge blocks less than half full or update key in
  43. * parent key if we deleted the first key in a block.
  44. *
  45. *
  46. * @parm HBT | hbt |
  47. * handle of the btree
  48. *
  49. * @parm KEY | key |
  50. * the key to delete from the btree
  51. *
  52. * @rdesc S_OK if delete works; ERR_NOTEXIST
  53. *
  54. * @rcomm Unfinished: doesn't do block merges or parent updates.
  55. *
  56. ***************************************************************************/
  57. PUBLIC HRESULT PASCAL FAR EXPORT_API RcDeleteHbt(HBT hbt, KEY key)
  58. {
  59. QBTHR qbthr;
  60. HF hf;
  61. HRESULT rc;
  62. QCB qcb;
  63. QB qb;
  64. SHORT cb;
  65. BTPOS btpos;
  66. if ((qbthr = (QBTHR)_GLOBALLOCK(hbt)) == NULL)
  67. return(E_INVALIDARG);
  68. hf = qbthr->hf;
  69. if (qbthr->bth.bFlags & fFSOpenReadOnly)
  70. {
  71. rc = E_NOPERMISSION;
  72. exit0:
  73. _GLOBALUNLOCK(hbt);
  74. return rc;
  75. }
  76. /* look up the key */
  77. if ((rc = RcLookupByKey(hbt, key, &btpos, NULL)) != S_OK)
  78. goto exit0;
  79. qbthr->qCache = _GLOBALLOCK(qbthr->ghCache);
  80. // copy over this key and rec with subsequent keys and recs
  81. if ((qcb = QCacheBlock(qbthr, qbthr->bth.cLevels - 1)) == NULL)
  82. {
  83. rc = E_FAIL;
  84. exit1:
  85. _GLOBALUNLOCK(qbthr->ghCache);
  86. goto exit0;
  87. }
  88. qb = qcb->db.rgbBlock + btpos.iKey;
  89. cb = CbSizeKey((KEY)qb, qbthr, TRUE);
  90. cb += CbSizeRec(qb + cb, qbthr);
  91. QVCOPY(qb, qb + cb, (LONG)(qbthr->bth.cbBlock +
  92. (QB)&(qcb->db) - qb - cb - qcb->db.cbSlack));
  93. qcb->db.cbSlack += cb;
  94. // if this was the first key in the leaf block, update key in parent
  95. // >>>>> code goes here
  96. // if block is now less than half full, merge blocks
  97. // >>>>> code goes here
  98. qcb->db.cKeys--;
  99. qcb->bFlags |= fCacheDirty;
  100. qbthr->bth.lcEntries--;
  101. qbthr->bth.bFlags |= fFSDirty;
  102. rc = S_OK;
  103. goto exit1;
  104. }
  105. /***************************************************************************\
  106. *
  107. * @doc PUBLIC API
  108. *
  109. * @func HRESULT PASCAL FAR | RcTraverseHbt |
  110. * Traverses entire btree, calling a user function at each entry.
  111. * Optionally, the user can cause the current entry to be deleted.
  112. *
  113. * @parm HBT | hbt |
  114. * handle of the btree
  115. *
  116. * @parm TRAVERSE_FUNC | fnCallback |
  117. * Callback of the form DWORD Callback(KEY key, QB rec, DWORD dwUser)
  118. * return TRAVERSE_DONE for normal exit, TRAVERSE_DELETE to delete this
  119. * entry, TRAVERSE_INTERRUPT to interrupt and stop traversing.
  120. *
  121. * @parm DWORD | dwUser |
  122. * User data that gets passed into the callback.
  123. *
  124. * @rdesc S_OK if delete works
  125. * @comm Assumes that RcDeleteHbt does not do block merges. Keys and
  126. * records are limited to 256 bytes in this function
  127. *
  128. ***************************************************************************/
  129. typedef DWORD (FAR PASCAL *TRAVERSE_FUNC) (KEY key, QB rec, DWORD dwUser);
  130. PUBLIC HRESULT PASCAL FAR EXPORT_API RcTraverseHbt(HBT hbt, TRAVERSE_FUNC fnCallback, DWORD dwUser)
  131. {
  132. QBTHR qbthr;
  133. HRESULT rc;
  134. BK bk;
  135. QCB qcb;
  136. QB qb;
  137. BTPOS btpos;
  138. BYTE * pKeyData;
  139. BYTE * pRecData;
  140. HRESULT errb;
  141. SHORT cbKey, cbRec;
  142. if ((hbt==NULL) || (!fnCallback))
  143. return E_INVALIDARG;
  144. if ((qbthr = (QBTHR)_GLOBALLOCK(hbt)) == NULL)
  145. return(E_INVALIDARG);
  146. if (qbthr->bth.lcEntries == (LONG)0)
  147. {
  148. rc = E_NOTEXIST;
  149. exit0:
  150. _GLOBALUNLOCK(hbt);
  151. return rc;
  152. }
  153. if ((bk = qbthr->bth.bkFirst) == bkNil)
  154. {
  155. rc = E_ASSERT;
  156. goto exit0;
  157. }
  158. if (qbthr->ghCache == NULL)
  159. {
  160. if ((rc = RcMakeCache(qbthr)) != S_OK)
  161. goto exit0;
  162. }
  163. qbthr->qCache = _GLOBALLOCK(qbthr->ghCache);
  164. if ((qcb = QFromBk(bk, (SHORT)(qbthr->bth.cLevels - 1), qbthr,
  165. &errb)) == NULL)
  166. {
  167. rc = errb;
  168. exit1:
  169. _GLOBALUNLOCK(qbthr->ghCache);
  170. goto exit0;
  171. }
  172. qb = qcb->db.rgbBlock + 2 * sizeof(BK);
  173. pKeyData=qb;
  174. cbKey = CbSizeKey((KEY)qb, qbthr, TRUE);
  175. qb += cbKey;
  176. pRecData=qb;
  177. cbRec = CbSizeRec(qb, qbthr);
  178. btpos.bk = bk;
  179. btpos.iKey = 2 * sizeof(BK);
  180. btpos.cKey = 0;
  181. while (1)
  182. {
  183. DWORD dwRes=(*fnCallback)((KEY)pKeyData,(QB)pRecData,dwUser);
  184. BTPOS btposNew;
  185. HRESULT errMore;
  186. errMore=RcNextPos( hbt, &btpos, &btposNew ); //==ERR_NOTEXIST)
  187. if (dwRes==1) // delete case
  188. {
  189. if (qbthr->bth.bFlags & fFSOpenReadOnly)
  190. {
  191. rc = E_NOPERMISSION;
  192. goto exit1;
  193. }
  194. // delete entry, and keep btposNew up to date during delete
  195. qcb = QFromBk(btpos.bk, (SHORT)(qbthr->bth.cLevels - 1), qbthr,&errb);
  196. //qb = qcb->db.rgbBlock + btpos.iKey;
  197. qb = qcb->db.rgbBlock + btpos.iKey;
  198. QVCOPY(qb, qb + cbKey + cbRec, (LONG)(qbthr->bth.cbBlock +
  199. (QB)&(qcb->db) - qb - (cbKey + cbRec) - qcb->db.cbSlack));
  200. qcb->db.cbSlack += cbKey + cbRec;
  201. qcb->db.cKeys--;
  202. qcb->bFlags |= fCacheDirty;
  203. qbthr->bth.lcEntries--;
  204. qbthr->bth.bFlags |= fFSDirty;
  205. if (btposNew.bk == btpos.bk)
  206. {
  207. btposNew.iKey-=cbKey + cbRec;
  208. btposNew.cKey--;
  209. }
  210. }
  211. else if (dwRes == 2)
  212. {
  213. rc = E_INTERRUPT;
  214. goto exit1;
  215. }
  216. if (errMore==S_OK)
  217. {
  218. btpos=btposNew;
  219. qcb = QFromBk(btpos.bk, (SHORT)(qbthr->bth.cLevels - 1), qbthr,&errb);
  220. qb = qcb->db.rgbBlock + btpos.iKey;
  221. pKeyData=qb;
  222. cbKey = CbSizeKey((KEY)qb, qbthr, TRUE);
  223. qb += cbKey;
  224. pRecData=qb;
  225. cbRec = CbSizeRec(qb, qbthr);
  226. }
  227. else
  228. break;
  229. }
  230. rc=S_OK;
  231. goto exit1;
  232. }
  233. /* EOF */