db_dup.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:7k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1996, 1997, 1998, 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: db_dup.c,v 11.18 2000/11/30 00:58:32 ubell Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #endif
  15. #include "db_int.h"
  16. #include "db_page.h"
  17. #include "db_shash.h"
  18. #include "btree.h"
  19. #include "hash.h"
  20. #include "lock.h"
  21. #include "db_am.h"
  22. /*
  23.  * __db_ditem --
  24.  * Remove an item from a page.
  25.  *
  26.  * PUBLIC:  int __db_ditem __P((DBC *, PAGE *, u_int32_t, u_int32_t));
  27.  */
  28. int
  29. __db_ditem(dbc, pagep, indx, nbytes)
  30. DBC *dbc;
  31. PAGE *pagep;
  32. u_int32_t indx, nbytes;
  33. {
  34. DB *dbp;
  35. DBT ldbt;
  36. db_indx_t cnt, offset;
  37. int ret;
  38. u_int8_t *from;
  39. dbp = dbc->dbp;
  40. if (DB_LOGGING(dbc)) {
  41. ldbt.data = P_ENTRY(pagep, indx);
  42. ldbt.size = nbytes;
  43. if ((ret = __db_addrem_log(dbp->dbenv, dbc->txn,
  44.     &LSN(pagep), 0, DB_REM_DUP, dbp->log_fileid, PGNO(pagep),
  45.     (u_int32_t)indx, nbytes, &ldbt, NULL, &LSN(pagep))) != 0)
  46. return (ret);
  47. }
  48. /*
  49.  * If there's only a single item on the page, we don't have to
  50.  * work hard.
  51.  */
  52. if (NUM_ENT(pagep) == 1) {
  53. NUM_ENT(pagep) = 0;
  54. HOFFSET(pagep) = dbp->pgsize;
  55. return (0);
  56. }
  57. /*
  58.  * Pack the remaining key/data items at the end of the page.  Use
  59.  * memmove(3), the regions may overlap.
  60.  */
  61. from = (u_int8_t *)pagep + HOFFSET(pagep);
  62. memmove(from + nbytes, from, pagep->inp[indx] - HOFFSET(pagep));
  63. HOFFSET(pagep) += nbytes;
  64. /* Adjust the indices' offsets. */
  65. offset = pagep->inp[indx];
  66. for (cnt = 0; cnt < NUM_ENT(pagep); ++cnt)
  67. if (pagep->inp[cnt] < offset)
  68. pagep->inp[cnt] += nbytes;
  69. /* Shift the indices down. */
  70. --NUM_ENT(pagep);
  71. if (indx != NUM_ENT(pagep))
  72. memmove(&pagep->inp[indx], &pagep->inp[indx + 1],
  73.     sizeof(db_indx_t) * (NUM_ENT(pagep) - indx));
  74. return (0);
  75. }
  76. /*
  77.  * __db_pitem --
  78.  * Put an item on a page.
  79.  *
  80.  * PUBLIC: int __db_pitem
  81.  * PUBLIC:     __P((DBC *, PAGE *, u_int32_t, u_int32_t, DBT *, DBT *));
  82.  */
  83. int
  84. __db_pitem(dbc, pagep, indx, nbytes, hdr, data)
  85. DBC *dbc;
  86. PAGE *pagep;
  87. u_int32_t indx;
  88. u_int32_t nbytes;
  89. DBT *hdr, *data;
  90. {
  91. DB *dbp;
  92. BKEYDATA bk;
  93. DBT thdr;
  94. int ret;
  95. u_int8_t *p;
  96. if (nbytes > P_FREESPACE(pagep)) {
  97. DB_ASSERT(nbytes <= P_FREESPACE(pagep));
  98. return (EINVAL);
  99. }
  100. /*
  101.  * Put a single item onto a page.  The logic figuring out where to
  102.  * insert and whether it fits is handled in the caller.  All we do
  103.  * here is manage the page shuffling.  We cheat a little bit in that
  104.  * we don't want to copy the dbt on a normal put twice.  If hdr is
  105.  * NULL, we create a BKEYDATA structure on the page, otherwise, just
  106.  * copy the caller's information onto the page.
  107.  *
  108.  * This routine is also used to put entries onto the page where the
  109.  * entry is pre-built, e.g., during recovery.  In this case, the hdr
  110.  * will point to the entry, and the data argument will be NULL.
  111.  *
  112.  * !!!
  113.  * There's a tremendous potential for off-by-one errors here, since
  114.  * the passed in header sizes must be adjusted for the structure's
  115.  * placeholder for the trailing variable-length data field.
  116.  */
  117. dbp = dbc->dbp;
  118. if (DB_LOGGING(dbc))
  119. if ((ret = __db_addrem_log(dbp->dbenv, dbc->txn,
  120.     &LSN(pagep), 0, DB_ADD_DUP, dbp->log_fileid, PGNO(pagep),
  121.     (u_int32_t)indx, nbytes, hdr, data, &LSN(pagep))) != 0)
  122. return (ret);
  123. if (hdr == NULL) {
  124. B_TSET(bk.type, B_KEYDATA, 0);
  125. bk.len = data == NULL ? 0 : data->size;
  126. thdr.data = &bk;
  127. thdr.size = SSZA(BKEYDATA, data);
  128. hdr = &thdr;
  129. }
  130. /* Adjust the index table, then put the item on the page. */
  131. if (indx != NUM_ENT(pagep))
  132. memmove(&pagep->inp[indx + 1], &pagep->inp[indx],
  133.     sizeof(db_indx_t) * (NUM_ENT(pagep) - indx));
  134. HOFFSET(pagep) -= nbytes;
  135. pagep->inp[indx] = HOFFSET(pagep);
  136. ++NUM_ENT(pagep);
  137. p = P_ENTRY(pagep, indx);
  138. memcpy(p, hdr->data, hdr->size);
  139. if (data != NULL)
  140. memcpy(p + hdr->size, data->data, data->size);
  141. return (0);
  142. }
  143. /*
  144.  * __db_relink --
  145.  * Relink around a deleted page.
  146.  *
  147.  * PUBLIC: int __db_relink __P((DBC *, u_int32_t, PAGE *, PAGE **, int));
  148.  */
  149. int
  150. __db_relink(dbc, add_rem, pagep, new_next, needlock)
  151. DBC *dbc;
  152. u_int32_t add_rem;
  153. PAGE *pagep, **new_next;
  154. int needlock;
  155. {
  156. DB *dbp;
  157. PAGE *np, *pp;
  158. DB_LOCK npl, ppl;
  159. DB_LSN *nlsnp, *plsnp, ret_lsn;
  160. int ret;
  161. ret = 0;
  162. np = pp = NULL;
  163. npl.off = ppl.off = LOCK_INVALID;
  164. nlsnp = plsnp = NULL;
  165. dbp = dbc->dbp;
  166. /*
  167.  * Retrieve and lock the one/two pages.  For a remove, we may need
  168.  * two pages (the before and after).  For an add, we only need one
  169.  * because, the split took care of the prev.
  170.  */
  171. if (pagep->next_pgno != PGNO_INVALID) {
  172. if (needlock && (ret = __db_lget(dbc,
  173.     0, pagep->next_pgno, DB_LOCK_WRITE, 0, &npl)) != 0)
  174. goto err;
  175. if ((ret = memp_fget(dbp->mpf,
  176.     &pagep->next_pgno, 0, &np)) != 0) {
  177. (void)__db_pgerr(dbp, pagep->next_pgno);
  178. goto err;
  179. }
  180. nlsnp = &np->lsn;
  181. }
  182. if (add_rem == DB_REM_PAGE && pagep->prev_pgno != PGNO_INVALID) {
  183. if (needlock && (ret = __db_lget(dbc,
  184.     0, pagep->prev_pgno, DB_LOCK_WRITE, 0, &ppl)) != 0)
  185. goto err;
  186. if ((ret = memp_fget(dbp->mpf,
  187.     &pagep->prev_pgno, 0, &pp)) != 0) {
  188. (void)__db_pgerr(dbp, pagep->next_pgno);
  189. goto err;
  190. }
  191. plsnp = &pp->lsn;
  192. }
  193. /* Log the change. */
  194. if (DB_LOGGING(dbc)) {
  195. if ((ret = __db_relink_log(dbp->dbenv, dbc->txn,
  196.     &ret_lsn, 0, add_rem, dbp->log_fileid,
  197.     pagep->pgno, &pagep->lsn,
  198.     pagep->prev_pgno, plsnp, pagep->next_pgno, nlsnp)) != 0)
  199. goto err;
  200. if (np != NULL)
  201. np->lsn = ret_lsn;
  202. if (pp != NULL)
  203. pp->lsn = ret_lsn;
  204. if (add_rem == DB_REM_PAGE)
  205. pagep->lsn = ret_lsn;
  206. }
  207. /*
  208.  * Modify and release the two pages.
  209.  *
  210.  * !!!
  211.  * The parameter new_next gets set to the page following the page we
  212.  * are removing.  If there is no following page, then new_next gets
  213.  * set to NULL.
  214.  */
  215. if (np != NULL) {
  216. if (add_rem == DB_ADD_PAGE)
  217. np->prev_pgno = pagep->pgno;
  218. else
  219. np->prev_pgno = pagep->prev_pgno;
  220. if (new_next == NULL)
  221. ret = memp_fput(dbp->mpf, np, DB_MPOOL_DIRTY);
  222. else {
  223. *new_next = np;
  224. ret = memp_fset(dbp->mpf, np, DB_MPOOL_DIRTY);
  225. }
  226. if (ret != 0)
  227. goto err;
  228. if (needlock)
  229. (void)__TLPUT(dbc, npl);
  230. } else if (new_next != NULL)
  231. *new_next = NULL;
  232. if (pp != NULL) {
  233. pp->next_pgno = pagep->next_pgno;
  234. if ((ret = memp_fput(dbp->mpf, pp, DB_MPOOL_DIRTY)) != 0)
  235. goto err;
  236. if (needlock)
  237. (void)__TLPUT(dbc, ppl);
  238. }
  239. return (0);
  240. err: if (np != NULL)
  241. (void)memp_fput(dbp->mpf, np, 0);
  242. if (needlock && npl.off != LOCK_INVALID)
  243. (void)__TLPUT(dbc, npl);
  244. if (pp != NULL)
  245. (void)memp_fput(dbp->mpf, pp, 0);
  246. if (needlock && ppl.off != LOCK_INVALID)
  247. (void)__TLPUT(dbc, ppl);
  248. return (ret);
  249. }