db_dup.c
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:7k
源码类别:

MySQL数据库

开发平台:

Visual C++

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