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

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. /*
  8.  * Copyright (c) 1995, 1996
  9.  * Margo Seltzer.  All rights reserved.
  10.  */
  11. /*
  12.  * Copyright (c) 1995, 1996
  13.  * The President and Fellows of Harvard University.  All rights reserved.
  14.  *
  15.  * This code is derived from software contributed to Berkeley by
  16.  * Margo Seltzer.
  17.  *
  18.  * Redistribution and use in source and binary forms, with or without
  19.  * modification, are permitted provided that the following conditions
  20.  * are met:
  21.  * 1. Redistributions of source code must retain the above copyright
  22.  *    notice, this list of conditions and the following disclaimer.
  23.  * 2. Redistributions in binary form must reproduce the above copyright
  24.  *    notice, this list of conditions and the following disclaimer in the
  25.  *    documentation and/or other materials provided with the distribution.
  26.  * 3. Neither the name of the University nor the names of its contributors
  27.  *    may be used to endorse or promote products derived from this software
  28.  *    without specific prior written permission.
  29.  *
  30.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  31.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  32.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  33.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  34.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  35.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  36.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  37.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  38.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  39.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  40.  * SUCH DAMAGE.
  41.  */
  42. #include "db_config.h"
  43. #ifndef lint
  44. static const char revid[] = "$Id: hash_rec.c,v 11.69 2002/09/03 14:12:49 margo Exp $";
  45. #endif /* not lint */
  46. #ifndef NO_SYSTEM_INCLUDES
  47. #include <sys/types.h>
  48. #include <string.h>
  49. #endif
  50. #include "db_int.h"
  51. #include "dbinc/db_page.h"
  52. #include "dbinc/btree.h"
  53. #include "dbinc/hash.h"
  54. #include "dbinc/log.h"
  55. static int __ham_alloc_pages __P((DB *, __ham_groupalloc_args *, DB_LSN *));
  56. /*
  57.  * __ham_insdel_recover --
  58.  *
  59.  * PUBLIC: int __ham_insdel_recover
  60.  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  61.  */
  62. int
  63. __ham_insdel_recover(dbenv, dbtp, lsnp, op, info)
  64. DB_ENV *dbenv;
  65. DBT *dbtp;
  66. DB_LSN *lsnp;
  67. db_recops op;
  68. void *info;
  69. {
  70. __ham_insdel_args *argp;
  71. DB *file_dbp;
  72. DBC *dbc;
  73. DB_MPOOLFILE *mpf;
  74. PAGE *pagep;
  75. u_int32_t flags, opcode;
  76. int cmp_n, cmp_p, ret, type;
  77. pagep = NULL;
  78. COMPQUIET(info, NULL);
  79. REC_PRINT(__ham_insdel_print);
  80. REC_INTRO(__ham_insdel_read, 1);
  81. if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
  82. if (DB_UNDO(op)) {
  83. /*
  84.  * We are undoing and the page doesn't exist.  That
  85.  * is equivalent to having a pagelsn of 0, so we
  86.  * would not have to undo anything.  In this case,
  87.  * don't bother creating a page.
  88.  */
  89. goto done;
  90. } else if ((ret = mpf->get(mpf,
  91.     &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  92. goto out;
  93. }
  94. cmp_n = log_compare(lsnp, &LSN(pagep));
  95. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  96. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  97. /*
  98.  * Two possible things going on:
  99.  * redo a delete/undo a put: delete the item from the page.
  100.  * redo a put/undo a delete: add the item to the page.
  101.  * If we are undoing a delete, then the information logged is the
  102.  * entire entry off the page, not just the data of a dbt.  In
  103.  * this case, we want to copy it back onto the page verbatim.
  104.  * We do this by calling __putitem with the type H_OFFPAGE instead
  105.  * of H_KEYDATA.
  106.  */
  107. opcode = OPCODE_OF(argp->opcode);
  108. flags = 0;
  109. if ((opcode == DELPAIR && cmp_n == 0 && DB_UNDO(op)) ||
  110.     (opcode == PUTPAIR && cmp_p == 0 && DB_REDO(op))) {
  111. /*
  112.  * Need to redo a PUT or undo a delete.  If we are undoing a
  113.  * delete, we've got to restore the item back to its original
  114.  * position.  That's a royal pain in the butt (because we do
  115.  * not store item lengths on the page), but there's no choice.
  116.  */
  117. if (opcode != DELPAIR ||
  118.     argp->ndx == (u_int32_t)NUM_ENT(pagep)) {
  119. __ham_putitem(file_dbp, pagep, &argp->key,
  120.     DB_UNDO(op) || PAIR_ISKEYBIG(argp->opcode) ?
  121.     H_OFFPAGE : H_KEYDATA);
  122. if (PAIR_ISDATADUP(argp->opcode))
  123. type = H_DUPLICATE;
  124. else if (DB_UNDO(op) || PAIR_ISDATABIG(argp->opcode))
  125. type = H_OFFPAGE;
  126. else
  127. type = H_KEYDATA;
  128. __ham_putitem(file_dbp, pagep, &argp->data, type);
  129. } else
  130. (void)__ham_reputpair(file_dbp, pagep,
  131.     argp->ndx, &argp->key, &argp->data);
  132. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
  133. flags = DB_MPOOL_DIRTY;
  134. } else if ((opcode == DELPAIR && cmp_p == 0 && DB_REDO(op)) ||
  135.     (opcode == PUTPAIR && cmp_n == 0 && DB_UNDO(op))) {
  136. /* Need to undo a put or redo a delete. */
  137. __ham_dpair(file_dbp, pagep, argp->ndx);
  138. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
  139. flags = DB_MPOOL_DIRTY;
  140. }
  141. if ((ret = mpf->put(mpf, pagep, flags)) != 0)
  142. goto out;
  143. pagep = NULL;
  144. /* Return the previous LSN. */
  145. done: *lsnp = argp->prev_lsn;
  146. ret = 0;
  147. out: if (pagep != NULL)
  148. (void)mpf->put(mpf, pagep, 0);
  149. REC_CLOSE;
  150. }
  151. /*
  152.  * __ham_newpage_recover --
  153.  * This log message is used when we add/remove overflow pages.  This
  154.  * message takes care of the pointer chains, not the data on the pages.
  155.  *
  156.  * PUBLIC: int __ham_newpage_recover
  157.  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  158.  */
  159. int
  160. __ham_newpage_recover(dbenv, dbtp, lsnp, op, info)
  161. DB_ENV *dbenv;
  162. DBT *dbtp;
  163. DB_LSN *lsnp;
  164. db_recops op;
  165. void *info;
  166. {
  167. __ham_newpage_args *argp;
  168. DB *file_dbp;
  169. DBC *dbc;
  170. DB_MPOOLFILE *mpf;
  171. PAGE *pagep;
  172. u_int32_t flags;
  173. int cmp_n, cmp_p, ret;
  174. pagep = NULL;
  175. COMPQUIET(info, NULL);
  176. REC_PRINT(__ham_newpage_print);
  177. REC_INTRO(__ham_newpage_read, 1);
  178. if ((ret = mpf->get(mpf, &argp->new_pgno, 0, &pagep)) != 0) {
  179. if (DB_UNDO(op)) {
  180. /*
  181.  * We are undoing and the page doesn't exist.  That
  182.  * is equivalent to having a pagelsn of 0, so we
  183.  * would not have to undo anything.  In this case,
  184.  * don't bother creating a page.
  185.  */
  186. ret = 0;
  187. goto ppage;
  188. } else if ((ret = mpf->get(mpf,
  189.     &argp->new_pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  190. goto out;
  191. }
  192. /*
  193.  * There are potentially three pages we need to check: the one
  194.  * that we created/deleted, the one before it and the one after
  195.  * it.
  196.  */
  197. cmp_n = log_compare(lsnp, &LSN(pagep));
  198. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  199. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  200. flags = 0;
  201. if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) ||
  202.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) {
  203. /* Redo a create new page or undo a delete new page. */
  204. P_INIT(pagep, file_dbp->pgsize, argp->new_pgno,
  205.     argp->prev_pgno, argp->next_pgno, 0, P_HASH);
  206. flags = DB_MPOOL_DIRTY;
  207. } else if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DELOVFL) ||
  208.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) {
  209. /*
  210.  * Redo a delete or undo a create new page.  All we
  211.  * really need to do is change the LSN.
  212.  */
  213. flags = DB_MPOOL_DIRTY;
  214. }
  215. if (flags)
  216. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
  217. if ((ret = mpf->put(mpf, pagep, flags)) != 0)
  218. goto out;
  219. pagep = NULL;
  220. /* Now do the prev page. */
  221. ppage: if (argp->prev_pgno != PGNO_INVALID) {
  222. if ((ret = mpf->get(mpf, &argp->prev_pgno, 0, &pagep)) != 0) {
  223. if (DB_UNDO(op)) {
  224. /*
  225.  * We are undoing and the page doesn't exist.
  226.  * That is equivalent to having a pagelsn of 0,
  227.  * so we would not have to undo anything.  In
  228.  * this case, don't bother creating a page.
  229.  */
  230. ret = 0;
  231. goto npage;
  232. } else if ((ret = mpf->get(mpf,
  233.     &argp->prev_pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  234. goto out;
  235. }
  236. cmp_n = log_compare(lsnp, &LSN(pagep));
  237. cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
  238. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->prevlsn);
  239. flags = 0;
  240. if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) ||
  241.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) {
  242. /* Redo a create new page or undo a delete new page. */
  243. pagep->next_pgno = argp->new_pgno;
  244. flags = DB_MPOOL_DIRTY;
  245. } else if ((cmp_p == 0 &&
  246.     DB_REDO(op) && argp->opcode == DELOVFL) ||
  247.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) {
  248. /* Redo a delete or undo a create new page. */
  249. pagep->next_pgno = argp->next_pgno;
  250. flags = DB_MPOOL_DIRTY;
  251. }
  252. if (flags)
  253. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->prevlsn;
  254. if ((ret = mpf->put(mpf, pagep, flags)) != 0)
  255. goto out;
  256. pagep = NULL;
  257. }
  258. /* Now time to do the next page */
  259. npage: if (argp->next_pgno != PGNO_INVALID) {
  260. if ((ret = mpf->get(mpf, &argp->next_pgno, 0, &pagep)) != 0) {
  261. if (DB_UNDO(op)) {
  262. /*
  263.  * We are undoing and the page doesn't exist.
  264.  * That is equivalent to having a pagelsn of 0,
  265.  * so we would not have to undo anything.  In
  266.  * this case, don't bother creating a page.
  267.  */
  268. goto done;
  269. } else if ((ret = mpf->get(mpf,
  270.     &argp->next_pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  271. goto out;
  272. }
  273. cmp_n = log_compare(lsnp, &LSN(pagep));
  274. cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
  275. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nextlsn);
  276. flags = 0;
  277. if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) ||
  278.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) {
  279. /* Redo a create new page or undo a delete new page. */
  280. pagep->prev_pgno = argp->new_pgno;
  281. flags = DB_MPOOL_DIRTY;
  282. } else if ((cmp_p == 0 &&
  283.     DB_REDO(op) && argp->opcode == DELOVFL) ||
  284.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) {
  285. /* Redo a delete or undo a create new page. */
  286. pagep->prev_pgno = argp->prev_pgno;
  287. flags = DB_MPOOL_DIRTY;
  288. }
  289. if (flags)
  290. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->nextlsn;
  291. if ((ret = mpf->put(mpf, pagep, flags)) != 0)
  292. goto out;
  293. pagep = NULL;
  294. }
  295. done: *lsnp = argp->prev_lsn;
  296. ret = 0;
  297. out: if (pagep != NULL)
  298. (void)mpf->put(mpf, pagep, 0);
  299. REC_CLOSE;
  300. }
  301. /*
  302.  * __ham_replace_recover --
  303.  * This log message refers to partial puts that are local to a single
  304.  * page.  You can think of them as special cases of the more general
  305.  * insdel log message.
  306.  *
  307.  * PUBLIC: int __ham_replace_recover
  308.  * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  309.  */
  310. int
  311. __ham_replace_recover(dbenv, dbtp, lsnp, op, info)
  312. DB_ENV *dbenv;
  313. DBT *dbtp;
  314. DB_LSN *lsnp;
  315. db_recops op;
  316. void *info;
  317. {
  318. __ham_replace_args *argp;
  319. DB *file_dbp;
  320. DBC *dbc;
  321. DB_MPOOLFILE *mpf;
  322. DBT dbt;
  323. PAGE *pagep;
  324. u_int32_t flags;
  325. int32_t grow;
  326. int cmp_n, cmp_p, ret;
  327. u_int8_t *hk;
  328. pagep = NULL;
  329. COMPQUIET(info, NULL);
  330. REC_PRINT(__ham_replace_print);
  331. REC_INTRO(__ham_replace_read, 1);
  332. if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
  333. if (DB_UNDO(op)) {
  334. /*
  335.  * We are undoing and the page doesn't exist.  That
  336.  * is equivalent to having a pagelsn of 0, so we
  337.  * would not have to undo anything.  In this case,
  338.  * don't bother creating a page.
  339.  */
  340. goto done;
  341. } else if ((ret = mpf->get(mpf,
  342.     &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  343. goto out;
  344. }
  345. cmp_n = log_compare(lsnp, &LSN(pagep));
  346. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  347. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  348. memset(&dbt, 0, sizeof(dbt));
  349. flags = 0;
  350. grow = 1;
  351. if (cmp_p == 0 && DB_REDO(op)) {
  352. /* Reapply the change as specified. */
  353. dbt.data = argp->newitem.data;
  354. dbt.size = argp->newitem.size;
  355. grow = argp->newitem.size - argp->olditem.size;
  356. LSN(pagep) = *lsnp;
  357. flags = DB_MPOOL_DIRTY;
  358. } else if (cmp_n == 0 && DB_UNDO(op)) {
  359. /* Undo the already applied change. */
  360. dbt.data = argp->olditem.data;
  361. dbt.size = argp->olditem.size;
  362. grow = argp->olditem.size - argp->newitem.size;
  363. LSN(pagep) = argp->pagelsn;
  364. flags = DB_MPOOL_DIRTY;
  365. }
  366. if (flags) {
  367. __ham_onpage_replace(file_dbp, pagep,
  368.     argp->ndx, argp->off, grow, &dbt);
  369. if (argp->makedup) {
  370. hk = P_ENTRY(file_dbp, pagep, argp->ndx);
  371. if (DB_REDO(op))
  372. HPAGE_PTYPE(hk) = H_DUPLICATE;
  373. else
  374. HPAGE_PTYPE(hk) = H_KEYDATA;
  375. }
  376. }
  377. if ((ret = mpf->put(mpf, pagep, flags)) != 0)
  378. goto out;
  379. pagep = NULL;
  380. done: *lsnp = argp->prev_lsn;
  381. ret = 0;
  382. out: if (pagep != NULL)
  383. (void)mpf->put(mpf, pagep, 0);
  384. REC_CLOSE;
  385. }
  386. /*
  387.  * __ham_splitdata_recover --
  388.  *
  389.  * PUBLIC: int __ham_splitdata_recover
  390.  * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  391.  */
  392. int
  393. __ham_splitdata_recover(dbenv, dbtp, lsnp, op, info)
  394. DB_ENV *dbenv;
  395. DBT *dbtp;
  396. DB_LSN *lsnp;
  397. db_recops op;
  398. void *info;
  399. {
  400. __ham_splitdata_args *argp;
  401. DB *file_dbp;
  402. DBC *dbc;
  403. DB_MPOOLFILE *mpf;
  404. PAGE *pagep;
  405. u_int32_t flags;
  406. int cmp_n, cmp_p, ret;
  407. pagep = NULL;
  408. COMPQUIET(info, NULL);
  409. REC_PRINT(__ham_splitdata_print);
  410. REC_INTRO(__ham_splitdata_read, 1);
  411. if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
  412. if (DB_UNDO(op)) {
  413. /*
  414.  * We are undoing and the page doesn't exist.  That
  415.  * is equivalent to having a pagelsn of 0, so we
  416.  * would not have to undo anything.  In this case,
  417.  * don't bother creating a page.
  418.  */
  419. goto done;
  420. } else if ((ret = mpf->get(mpf,
  421.     &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  422. goto out;
  423. }
  424. cmp_n = log_compare(lsnp, &LSN(pagep));
  425. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  426. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  427. /*
  428.  * There are two types of log messages here, one for the old page
  429.  * and one for the new pages created.  The original image in the
  430.  * SPLITOLD record is used for undo.  The image in the SPLITNEW
  431.  * is used for redo.  We should never have a case where there is
  432.  * a redo operation and the SPLITOLD record is on disk, but not
  433.  * the SPLITNEW record.  Therefore, we only have work to do when
  434.  * redo NEW messages and undo OLD messages, but we have to update
  435.  * LSNs in both cases.
  436.  */
  437. flags = 0;
  438. if (cmp_p == 0 && DB_REDO(op)) {
  439. if (argp->opcode == SPLITNEW)
  440. /* Need to redo the split described. */
  441. memcpy(pagep, argp->pageimage.data,
  442.     argp->pageimage.size);
  443. LSN(pagep) = *lsnp;
  444. flags = DB_MPOOL_DIRTY;
  445. } else if (cmp_n == 0 && DB_UNDO(op)) {
  446. if (argp->opcode == SPLITOLD) {
  447. /* Put back the old image. */
  448. memcpy(pagep, argp->pageimage.data,
  449.     argp->pageimage.size);
  450. } else
  451. P_INIT(pagep, file_dbp->pgsize, argp->pgno,
  452.     PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
  453. LSN(pagep) = argp->pagelsn;
  454. flags = DB_MPOOL_DIRTY;
  455. }
  456. if ((ret = mpf->put(mpf, pagep, flags)) != 0)
  457. goto out;
  458. pagep = NULL;
  459. done: *lsnp = argp->prev_lsn;
  460. ret = 0;
  461. out: if (pagep != NULL)
  462. (void)mpf->put(mpf, pagep, 0);
  463. REC_CLOSE;
  464. }
  465. /*
  466.  * __ham_copypage_recover --
  467.  * Recovery function for copypage.
  468.  *
  469.  * PUBLIC: int __ham_copypage_recover
  470.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  471.  */
  472. int
  473. __ham_copypage_recover(dbenv, dbtp, lsnp, op, info)
  474. DB_ENV *dbenv;
  475. DBT *dbtp;
  476. DB_LSN *lsnp;
  477. db_recops op;
  478. void *info;
  479. {
  480. __ham_copypage_args *argp;
  481. DB *file_dbp;
  482. DBC *dbc;
  483. DB_MPOOLFILE *mpf;
  484. PAGE *pagep;
  485. u_int32_t flags;
  486. int cmp_n, cmp_p, ret;
  487. pagep = NULL;
  488. COMPQUIET(info, NULL);
  489. REC_PRINT(__ham_copypage_print);
  490. REC_INTRO(__ham_copypage_read, 1);
  491. flags = 0;
  492. /* This is the bucket page. */
  493. if ((ret = mpf->get(mpf, &argp->pgno, 0, &pagep)) != 0) {
  494. if (DB_UNDO(op)) {
  495. /*
  496.  * We are undoing and the page doesn't exist.  That
  497.  * is equivalent to having a pagelsn of 0, so we
  498.  * would not have to undo anything.  In this case,
  499.  * don't bother creating a page.
  500.  */
  501. ret = 0;
  502. goto donext;
  503. } else if ((ret = mpf->get(mpf,
  504.     &argp->pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  505. goto out;
  506. }
  507. cmp_n = log_compare(lsnp, &LSN(pagep));
  508. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  509. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  510. if (cmp_p == 0 && DB_REDO(op)) {
  511. /* Need to redo update described. */
  512. memcpy(pagep, argp->page.data, argp->page.size);
  513. PGNO(pagep) = argp->pgno;
  514. PREV_PGNO(pagep) = PGNO_INVALID;
  515. LSN(pagep) = *lsnp;
  516. flags = DB_MPOOL_DIRTY;
  517. } else if (cmp_n == 0 && DB_UNDO(op)) {
  518. /* Need to undo update described. */
  519. P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID,
  520.     argp->next_pgno, 0, P_HASH);
  521. LSN(pagep) = argp->pagelsn;
  522. flags = DB_MPOOL_DIRTY;
  523. }
  524. if ((ret = mpf->put(mpf, pagep, flags)) != 0)
  525. goto out;
  526. pagep = NULL;
  527. donext: /* Now fix up the "next" page. */
  528. if ((ret = mpf->get(mpf, &argp->next_pgno, 0, &pagep)) != 0) {
  529. if (DB_UNDO(op)) {
  530. /*
  531.  * We are undoing and the page doesn't exist.  That
  532.  * is equivalent to having a pagelsn of 0, so we
  533.  * would not have to undo anything.  In this case,
  534.  * don't bother creating a page.
  535.  */
  536. ret = 0;
  537. goto do_nn;
  538. } else if ((ret = mpf->get(mpf,
  539.     &argp->next_pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  540. goto out;
  541. }
  542. /* For REDO just update the LSN. For UNDO copy page back. */
  543. cmp_n = log_compare(lsnp, &LSN(pagep));
  544. cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
  545. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nextlsn);
  546. flags = 0;
  547. if (cmp_p == 0 && DB_REDO(op)) {
  548. LSN(pagep) = *lsnp;
  549. flags = DB_MPOOL_DIRTY;
  550. } else if (cmp_n == 0 && DB_UNDO(op)) {
  551. /* Need to undo update described. */
  552. memcpy(pagep, argp->page.data, argp->page.size);
  553. flags = DB_MPOOL_DIRTY;
  554. }
  555. if ((ret = mpf->put(mpf, pagep, flags)) != 0)
  556. goto out;
  557. pagep = NULL;
  558. /* Now fix up the next's next page. */
  559. do_nn: if (argp->nnext_pgno == PGNO_INVALID)
  560. goto done;
  561. if ((ret = mpf->get(mpf, &argp->nnext_pgno, 0, &pagep)) != 0) {
  562. if (DB_UNDO(op)) {
  563. /*
  564.  * We are undoing and the page doesn't exist.  That
  565.  * is equivalent to having a pagelsn of 0, so we
  566.  * would not have to undo anything.  In this case,
  567.  * don't bother creating a page.
  568.  */
  569. goto done;
  570. } else if ((ret = mpf->get(mpf,
  571.     &argp->nnext_pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  572. goto out;
  573. }
  574. cmp_n = log_compare(lsnp, &LSN(pagep));
  575. cmp_p = log_compare(&LSN(pagep), &argp->nnextlsn);
  576. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nnextlsn);
  577. flags = 0;
  578. if (cmp_p == 0 && DB_REDO(op)) {
  579. /* Need to redo update described. */
  580. PREV_PGNO(pagep) = argp->pgno;
  581. LSN(pagep) = *lsnp;
  582. flags = DB_MPOOL_DIRTY;
  583. } else if (cmp_n == 0 && DB_UNDO(op)) {
  584. /* Need to undo update described. */
  585. PREV_PGNO(pagep) = argp->next_pgno;
  586. LSN(pagep) = argp->nnextlsn;
  587. flags = DB_MPOOL_DIRTY;
  588. }
  589. if ((ret = mpf->put(mpf, pagep, flags)) != 0)
  590. goto out;
  591. pagep = NULL;
  592. done: *lsnp = argp->prev_lsn;
  593. ret = 0;
  594. out: if (pagep != NULL)
  595. (void)mpf->put(mpf, pagep, 0);
  596. REC_CLOSE;
  597. }
  598. /*
  599.  * __ham_metagroup_recover --
  600.  * Recovery function for metagroup.
  601.  *
  602.  * PUBLIC: int __ham_metagroup_recover
  603.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  604.  */
  605. int
  606. __ham_metagroup_recover(dbenv, dbtp, lsnp, op, info)
  607. DB_ENV *dbenv;
  608. DBT *dbtp;
  609. DB_LSN *lsnp;
  610. db_recops op;
  611. void *info;
  612. {
  613. __ham_metagroup_args *argp;
  614. HASH_CURSOR *hcp;
  615. DB *file_dbp;
  616. DBMETA *mmeta;
  617. DBC *dbc;
  618. DB_MPOOLFILE *mpf;
  619. PAGE *pagep;
  620. db_pgno_t pgno;
  621. u_int32_t flags, mmeta_flags;
  622. int cmp_n, cmp_p, did_recover, groupgrow, ret;
  623. COMPQUIET(info, NULL);
  624. mmeta_flags = 0;
  625. mmeta = NULL;
  626. REC_PRINT(__ham_metagroup_print);
  627. REC_INTRO(__ham_metagroup_read, 1);
  628. /*
  629.  * This logs the virtual create of pages pgno to pgno + bucket
  630.  * Since the mpool page-allocation is not really able to be
  631.  * transaction protected, we can never undo it.  Even in an abort,
  632.  * we have to allocate these pages to the hash table if they
  633.  * were actually created.  In particular, during disaster
  634.  * recovery the metapage may be before this point if we
  635.  * are rolling backward.  If the file has not been extended
  636.  * then the metapage could not have been updated.
  637.  * The log record contains:
  638.  * bucket: new bucket being allocated.
  639.  * pgno: page number of the new bucket.
  640.  * if bucket is a power of 2, then we allocated a whole batch of
  641.  * pages; if it's not, then we simply allocated one new page.
  642.  */
  643. groupgrow = (u_int32_t)(1 << __db_log2(argp->bucket + 1)) ==
  644.     argp->bucket + 1;
  645. pgno = argp->pgno;
  646. if (argp->newalloc)
  647. pgno += argp->bucket;
  648. if ((ret = mpf->get(mpf, &pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  649. goto out;
  650. cmp_n = log_compare(lsnp, &LSN(pagep));
  651. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  652. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  653. flags = 0;
  654. if ((cmp_p == 0 && DB_REDO(op)) || (cmp_n == 0 && DB_UNDO(op))) {
  655. /*
  656.  * We need to make sure that we redo the allocation of the
  657.  * pages.
  658.  */
  659. if (DB_REDO(op))
  660. pagep->lsn = *lsnp;
  661. else
  662. pagep->lsn = argp->pagelsn;
  663. flags = DB_MPOOL_DIRTY;
  664. }
  665. if ((ret = mpf->put(mpf, pagep, flags)) != 0)
  666. goto out;
  667. /* Now we have to update the meta-data page. */
  668. hcp = (HASH_CURSOR *)dbc->internal;
  669. if ((ret = __ham_get_meta(dbc)) != 0)
  670. goto out;
  671. cmp_n = log_compare(lsnp, &hcp->hdr->dbmeta.lsn);
  672. cmp_p = log_compare(&hcp->hdr->dbmeta.lsn, &argp->metalsn);
  673. CHECK_LSN(op, cmp_p, &hcp->hdr->dbmeta.lsn, &argp->metalsn);
  674. did_recover = 0;
  675. if (cmp_p == 0 && DB_REDO(op)) {
  676. /* Redo the actual updating of bucket counts. */
  677. ++hcp->hdr->max_bucket;
  678. if (groupgrow) {
  679. hcp->hdr->low_mask = hcp->hdr->high_mask;
  680. hcp->hdr->high_mask =
  681.     (argp->bucket + 1) | hcp->hdr->low_mask;
  682. }
  683. hcp->hdr->dbmeta.lsn = *lsnp;
  684. did_recover = 1;
  685. } else if (cmp_n == 0 && DB_UNDO(op)) {
  686. /* Undo the actual updating of bucket counts. */
  687. --hcp->hdr->max_bucket;
  688. if (groupgrow) {
  689. hcp->hdr->high_mask = hcp->hdr->low_mask;
  690. hcp->hdr->low_mask = hcp->hdr->high_mask >> 1;
  691. }
  692. hcp->hdr->dbmeta.lsn = argp->metalsn;
  693. did_recover = 1;
  694. }
  695. /*
  696.  * Now we need to fix up the spares array.  Each entry in the
  697.  * spares array indicates the beginning page number for the
  698.  * indicated doubling.  We need to fill this in whenever the
  699.  * spares array is invalid, since we never reclaim pages from
  700.  * the spares array and we have to allocate the pages to the
  701.  * spares array in both the redo and undo cases.
  702.  */
  703. if (argp->newalloc &&
  704.     hcp->hdr->spares[__db_log2(argp->bucket + 1) + 1] == PGNO_INVALID) {
  705. hcp->hdr->spares[__db_log2(argp->bucket + 1) + 1] =
  706.     argp->pgno - argp->bucket - 1;
  707. did_recover = 1;
  708. }
  709. /*
  710.  * Finally, we need to potentially fix up the last_pgno field
  711.  * in the master meta-data page (which may or may not be the
  712.  * same as the hash header page).
  713.  */
  714. if (argp->mmpgno != argp->mpgno) {
  715. if ((ret =
  716.     mpf->get(mpf, &argp->mmpgno, 0, (PAGE **)&mmeta)) != 0)
  717. goto out;
  718. mmeta_flags = 0;
  719. cmp_n = log_compare(lsnp, &mmeta->lsn);
  720. cmp_p = log_compare(&mmeta->lsn, &argp->mmetalsn);
  721. if (cmp_p == 0 && DB_REDO(op)) {
  722. mmeta->lsn = *lsnp;
  723. mmeta_flags = DB_MPOOL_DIRTY;
  724. } else if (cmp_n == 0 && DB_UNDO(op)) {
  725. mmeta->lsn = argp->mmetalsn;
  726. mmeta_flags = DB_MPOOL_DIRTY;
  727. }
  728. } else
  729. mmeta = (DBMETA *)hcp->hdr;
  730. if (argp->newalloc) {
  731. if (mmeta->last_pgno < pgno)
  732. mmeta->last_pgno = pgno;
  733. mmeta_flags = DB_MPOOL_DIRTY;
  734. }
  735. if (argp->mmpgno != argp->mpgno &&
  736.     (ret = mpf->put(mpf, mmeta, mmeta_flags)) != 0)
  737. goto out;
  738. mmeta = NULL;
  739. if (did_recover)
  740. F_SET(hcp, H_DIRTY);
  741. done: *lsnp = argp->prev_lsn;
  742. ret = 0;
  743. out: if (mmeta != NULL)
  744. (void)mpf->put(mpf, mmeta, 0);
  745. if (dbc != NULL)
  746. (void)__ham_release_meta(dbc);
  747. if (ret == ENOENT && op == DB_TXN_BACKWARD_ALLOC)
  748. ret = 0;
  749. REC_CLOSE;
  750. }
  751. /*
  752.  * __ham_groupalloc_recover --
  753.  * Recover the batch creation of a set of pages for a new database.
  754.  *
  755.  * PUBLIC: int __ham_groupalloc_recover
  756.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  757.  */
  758. int
  759. __ham_groupalloc_recover(dbenv, dbtp, lsnp, op, info)
  760. DB_ENV *dbenv;
  761. DBT *dbtp;
  762. DB_LSN *lsnp;
  763. db_recops op;
  764. void *info;
  765. {
  766. __ham_groupalloc_args *argp;
  767. DBMETA *mmeta;
  768. DB_MPOOLFILE *mpf;
  769. DB *file_dbp;
  770. DBC *dbc;
  771. PAGE *pagep;
  772. db_pgno_t pgno;
  773. int cmp_n, cmp_p, modified, ret;
  774. mmeta = NULL;
  775. modified = 0;
  776. REC_PRINT(__ham_groupalloc_print);
  777. REC_INTRO(__ham_groupalloc_read, 0);
  778. pgno = PGNO_BASE_MD;
  779. if ((ret = mpf->get(mpf, &pgno, 0, &mmeta)) != 0) {
  780. if (DB_REDO(op)) {
  781. /* Page should have existed. */
  782. __db_pgerr(file_dbp, pgno, ret);
  783. goto out;
  784. } else {
  785. ret = 0;
  786. goto done;
  787. }
  788. }
  789. cmp_n = log_compare(lsnp, &LSN(mmeta));
  790. cmp_p = log_compare(&LSN(mmeta), &argp->meta_lsn);
  791. CHECK_LSN(op, cmp_p, &LSN(mmeta), &argp->meta_lsn);
  792. /*
  793.  * Basically, we used mpool to allocate a chunk of pages.
  794.  * We need to either add those to a free list (in the undo
  795.  * case) or initialize them (in the redo case).
  796.  *
  797.  * If we are redoing and this is a hash subdatabase, it's possible
  798.  * that the pages were never allocated, so we'd better check for
  799.  * that and handle it here.
  800.  */
  801. if (DB_REDO(op)) {
  802. if ((ret = __ham_alloc_pages(file_dbp, argp, lsnp)) != 0)
  803. goto out;
  804. if (cmp_p == 0) {
  805. LSN(mmeta) = *lsnp;
  806. modified = 1;
  807. }
  808. } else if (DB_UNDO(op)) {
  809. /*
  810.  * Reset the last page back to its preallocation state.
  811.  */
  812. pgno = argp->start_pgno + argp->num - 1;
  813. if ((ret = mpf->get(mpf, &pgno, 0, &pagep)) == 0) {
  814. if (log_compare(&pagep->lsn, lsnp) == 0)
  815. ZERO_LSN(pagep->lsn);
  816. if ((ret = mpf->put(mpf, pagep, DB_MPOOL_DIRTY)) != 0)
  817. goto out;
  818. } else if (ret != DB_PAGE_NOTFOUND)
  819. goto out;
  820. /*
  821.  * Always put the pages into the limbo list and free them later.
  822.  */
  823. if ((ret = __db_add_limbo(dbenv,
  824.     info, argp->fileid, argp->start_pgno, argp->num)) != 0)
  825. goto out;
  826. if (cmp_n == 0) {
  827. LSN(mmeta) = argp->meta_lsn;
  828. modified = 1;
  829. }
  830. }
  831. done: if (ret == 0)
  832. *lsnp = argp->prev_lsn;
  833. out: if (mmeta != NULL)
  834. (void)mpf->put(mpf, mmeta, modified ? DB_MPOOL_DIRTY : 0);
  835. if (ret == ENOENT && op == DB_TXN_BACKWARD_ALLOC)
  836. ret = 0;
  837. REC_CLOSE;
  838. }
  839. /*
  840.  * __ham_alloc_pages --
  841.  *
  842.  * Called during redo of a file create.  We create new pages in the file
  843.  * using the MPOOL_NEW_GROUP flag.  We then log the meta-data page with a
  844.  * __crdel_metasub message.  If we manage to crash without the newly written
  845.  * pages getting to disk (I'm not sure this can happen anywhere except our
  846.  * test suite?!), then we need to go through a recreate the final pages.
  847.  * Hash normally has holes in its files and handles them appropriately.
  848.  */
  849. static int
  850. __ham_alloc_pages(dbp, argp, lsnp)
  851. DB *dbp;
  852. __ham_groupalloc_args *argp;
  853. DB_LSN *lsnp;
  854. {
  855. DB_MPOOLFILE *mpf;
  856. PAGE *pagep;
  857. db_pgno_t pgno;
  858. int ret;
  859. mpf = dbp->mpf;
  860. /* Read the last page of the allocation. */
  861. pgno = argp->start_pgno + argp->num - 1;
  862. /* If the page exists, and it has been initialized, then we're done. */
  863. if ((ret = mpf->get(mpf, &pgno, 0, &pagep)) == 0) {
  864. if (NUM_ENT(pagep) == 0 && IS_ZERO_LSN(pagep->lsn))
  865. goto reinit_page;
  866. if ((ret = mpf->put(mpf, pagep, 0)) != 0)
  867. return (ret);
  868. return (0);
  869. }
  870. /* Had to create the page. */
  871. if ((ret = mpf->get(mpf, &pgno, DB_MPOOL_CREATE, &pagep)) != 0) {
  872. __db_pgerr(dbp, pgno, ret);
  873. return (ret);
  874. }
  875. reinit_page:
  876. /* Initialize the newly allocated page. */
  877. P_INIT(pagep, dbp->pgsize, pgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
  878. pagep->lsn = *lsnp;
  879. if ((ret = mpf->put(mpf, pagep, DB_MPOOL_DIRTY)) != 0)
  880. return (ret);
  881. return (0);
  882. }
  883. /*
  884.  * __ham_curadj_recover --
  885.  * Undo cursor adjustments if a subtransaction fails.
  886.  *
  887.  * PUBLIC: int __ham_curadj_recover
  888.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  889.  */
  890. int
  891. __ham_curadj_recover(dbenv, dbtp, lsnp, op, info)
  892. DB_ENV *dbenv;
  893. DBT *dbtp;
  894. DB_LSN *lsnp;
  895. db_recops op;
  896. void *info;
  897. {
  898. __ham_curadj_args *argp;
  899. DB_MPOOLFILE *mpf;
  900. DB *file_dbp;
  901. DBC *dbc;
  902. int ret;
  903. HASH_CURSOR *hcp;
  904. COMPQUIET(info, NULL);
  905. REC_PRINT(__ham_curadj_print);
  906. REC_INTRO(__ham_curadj_read, 0);
  907. if (op != DB_TXN_ABORT)
  908. goto done;
  909. /*
  910.  * Undo the adjustment by reinitializing the the cursor
  911.  * to look like the one that was used to do the adustment,
  912.  * then we invert the add so that undo the adjustment.
  913.  */
  914. hcp = (HASH_CURSOR *)dbc->internal;
  915. hcp->pgno = argp->pgno;
  916. hcp->indx = argp->indx;
  917. hcp->dup_off = argp->dup_off;
  918. hcp->order = argp->order;
  919. if (!argp->add)
  920. F_SET(hcp, H_DELETED);
  921. (void)__ham_c_update(dbc, argp->len, !argp->add, argp->is_dup);
  922. done: *lsnp = argp->prev_lsn;
  923. out: REC_CLOSE;
  924. }
  925. /*
  926.  * __ham_chgpg_recover --
  927.  * Undo cursor adjustments if a subtransaction fails.
  928.  *
  929.  * PUBLIC: int __ham_chgpg_recover
  930.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  931.  */
  932. int
  933. __ham_chgpg_recover(dbenv, dbtp, lsnp, op, info)
  934. DB_ENV *dbenv;
  935. DBT *dbtp;
  936. DB_LSN *lsnp;
  937. db_recops op;
  938. void *info;
  939. {
  940. __ham_chgpg_args *argp;
  941. BTREE_CURSOR *opdcp;
  942. DB_MPOOLFILE *mpf;
  943. DB *file_dbp, *ldbp;
  944. DBC *dbc;
  945. int ret;
  946. DBC *cp;
  947. HASH_CURSOR *lcp;
  948. u_int32_t order, indx;
  949. COMPQUIET(info, NULL);
  950. REC_PRINT(__ham_chgpg_print);
  951. REC_INTRO(__ham_chgpg_read, 0);
  952. if (op != DB_TXN_ABORT)
  953. goto done;
  954. /* Overloaded fields for DB_HAM_DEL*PG */
  955. indx = argp->old_indx;
  956. order = argp->new_indx;
  957. MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
  958. for (ldbp = __dblist_get(dbenv, file_dbp->adj_fileid);
  959.     ldbp != NULL && ldbp->adj_fileid == file_dbp->adj_fileid;
  960.     ldbp = LIST_NEXT(ldbp, dblistlinks)) {
  961. MUTEX_THREAD_LOCK(dbenv, file_dbp->mutexp);
  962. for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL;
  963.     cp = TAILQ_NEXT(cp, links)) {
  964. lcp = (HASH_CURSOR *)cp->internal;
  965. switch (argp->mode) {
  966. case DB_HAM_DELFIRSTPG:
  967. if (lcp->pgno != argp->new_pgno)
  968. break;
  969. if (lcp->indx != indx ||
  970.     !F_ISSET(lcp, H_DELETED) ||
  971.     lcp->order >= order) {
  972. lcp->pgno = argp->old_pgno;
  973. if (lcp->indx == indx)
  974. lcp->order -= order;
  975. }
  976. break;
  977. case DB_HAM_DELMIDPG:
  978. case DB_HAM_DELLASTPG:
  979. if (lcp->pgno == argp->new_pgno &&
  980.     lcp->indx == indx &&
  981.     F_ISSET(lcp, H_DELETED) &&
  982.     lcp->order >= order) {
  983. lcp->pgno = argp->old_pgno;
  984. lcp->order -= order;
  985. lcp->indx = 0;
  986. }
  987. break;
  988. case DB_HAM_CHGPG:
  989. /*
  990.  * If we're doing a CHGPG, we're undoing
  991.  * the move of a non-deleted item to a
  992.  * new page.  Any cursors with the deleted
  993.  * flag set do not belong to this item;
  994.  * don't touch them.
  995.  */
  996. if (F_ISSET(lcp, H_DELETED))
  997. break;
  998. /* FALLTHROUGH */
  999. case DB_HAM_SPLIT:
  1000. if (lcp->pgno == argp->new_pgno &&
  1001.     lcp->indx == argp->new_indx) {
  1002. lcp->indx = argp->old_indx;
  1003. lcp->pgno = argp->old_pgno;
  1004. }
  1005. break;
  1006. case DB_HAM_DUP:
  1007. if (lcp->opd == NULL)
  1008. break;
  1009. opdcp = (BTREE_CURSOR *)lcp->opd->internal;
  1010. if (opdcp->pgno != argp->new_pgno ||
  1011.     opdcp->indx != argp->new_indx)
  1012. break;
  1013. if (F_ISSET(opdcp, C_DELETED))
  1014. F_SET(lcp, H_DELETED);
  1015. /*
  1016.  * We can't close a cursor while we have the
  1017.  * dbp mutex locked, since c_close reacquires
  1018.  * it.  It should be safe to drop the mutex
  1019.  * here, though, since newly opened cursors
  1020.  * are put only at the end of the tailq and
  1021.  * the cursor we're adjusting can't be closed
  1022.  * under us.
  1023.  */
  1024. MUTEX_THREAD_UNLOCK(dbenv, file_dbp->mutexp);
  1025. if ((ret = lcp->opd->c_close(lcp->opd)) != 0)
  1026. goto out;
  1027. MUTEX_THREAD_LOCK(dbenv, file_dbp->mutexp);
  1028. lcp->opd = NULL;
  1029. break;
  1030. }
  1031. }
  1032. MUTEX_THREAD_UNLOCK(dbenv, file_dbp->mutexp);
  1033. }
  1034. MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
  1035. done: *lsnp = argp->prev_lsn;
  1036. out: REC_CLOSE;
  1037. }