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

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. /*
  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.34 2001/01/11 18:19:52 bostic 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 "db_page.h"
  52. #include "db_shash.h"
  53. #include "btree.h"
  54. #include "hash.h"
  55. #include "lock.h"
  56. #include "log.h"
  57. #include "mp.h"
  58. static int __ham_alloc_pages __P((DB *, __ham_groupalloc_args *));
  59. /*
  60.  * __ham_insdel_recover --
  61.  *
  62.  * PUBLIC: int __ham_insdel_recover
  63.  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  64.  */
  65. int
  66. __ham_insdel_recover(dbenv, dbtp, lsnp, op, info)
  67. DB_ENV *dbenv;
  68. DBT *dbtp;
  69. DB_LSN *lsnp;
  70. db_recops op;
  71. void *info;
  72. {
  73. __ham_insdel_args *argp;
  74. DB *file_dbp;
  75. DBC *dbc;
  76. DB_MPOOLFILE *mpf;
  77. PAGE *pagep;
  78. u_int32_t opcode;
  79. int cmp_n, cmp_p, flags, getmeta, ret, type;
  80. COMPQUIET(info, NULL);
  81. getmeta = 0;
  82. REC_PRINT(__ham_insdel_print);
  83. REC_INTRO(__ham_insdel_read, 1);
  84. if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
  85. if (DB_UNDO(op)) {
  86. /*
  87.  * We are undoing and the page doesn't exist.  That
  88.  * is equivalent to having a pagelsn of 0, so we
  89.  * would not have to undo anything.  In this case,
  90.  * don't bother creating a page.
  91.  */
  92. goto done;
  93. } else if ((ret = memp_fget(mpf, &argp->pgno,
  94.     DB_MPOOL_CREATE, &pagep)) != 0)
  95. goto out;
  96. }
  97. if ((ret = __ham_get_meta(dbc)) != 0)
  98. goto out;
  99. getmeta = 1;
  100. cmp_n = log_compare(lsnp, &LSN(pagep));
  101. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  102. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  103. /*
  104.  * Two possible things going on:
  105.  * redo a delete/undo a put: delete the item from the page.
  106.  * redo a put/undo a delete: add the item to the page.
  107.  * If we are undoing a delete, then the information logged is the
  108.  * entire entry off the page, not just the data of a dbt.  In
  109.  * this case, we want to copy it back onto the page verbatim.
  110.  * We do this by calling __putitem with the type H_OFFPAGE instead
  111.  * of H_KEYDATA.
  112.  */
  113. opcode = OPCODE_OF(argp->opcode);
  114. flags = 0;
  115. if ((opcode == DELPAIR && cmp_n == 0 && DB_UNDO(op)) ||
  116.     (opcode == PUTPAIR && cmp_p == 0 && DB_REDO(op))) {
  117. /*
  118.  * Need to redo a PUT or undo a delete.  If we are undoing a
  119.  * delete, we've got to restore the item back to its original
  120.  * position.  That's a royal pain in the butt (because we do
  121.  * not store item lengths on the page), but there's no choice.
  122.  */
  123. if (opcode != DELPAIR ||
  124.     argp->ndx == (u_int32_t)NUM_ENT(pagep)) {
  125. __ham_putitem(pagep, &argp->key,
  126.     DB_UNDO(op) || PAIR_ISKEYBIG(argp->opcode) ?
  127.     H_OFFPAGE : H_KEYDATA);
  128. if (PAIR_ISDATADUP(argp->opcode))
  129. type = H_DUPLICATE;
  130. else if (DB_UNDO(op) || PAIR_ISDATABIG(argp->opcode))
  131. type = H_OFFPAGE;
  132. else
  133. type = H_KEYDATA;
  134. __ham_putitem(pagep, &argp->data, type);
  135. } else
  136. (void)__ham_reputpair(pagep, file_dbp->pgsize,
  137.     argp->ndx, &argp->key, &argp->data);
  138. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
  139. flags = DB_MPOOL_DIRTY;
  140. } else if ((opcode == DELPAIR && cmp_p == 0 && DB_REDO(op))
  141.     || (opcode == PUTPAIR && cmp_n == 0 && DB_UNDO(op))) {
  142. /* Need to undo a put or redo a delete. */
  143. __ham_dpair(file_dbp, pagep, argp->ndx);
  144. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
  145. flags = DB_MPOOL_DIRTY;
  146. }
  147. if ((ret = memp_fput(file_dbp->mpf, pagep, flags)) != 0)
  148. goto out;
  149. /* Return the previous LSN. */
  150. done: *lsnp = argp->prev_lsn;
  151. ret = 0;
  152. out: if (getmeta)
  153. (void)__ham_release_meta(dbc);
  154. REC_CLOSE;
  155. }
  156. /*
  157.  * __ham_newpage_recover --
  158.  * This log message is used when we add/remove overflow pages.  This
  159.  * message takes care of the pointer chains, not the data on the pages.
  160.  *
  161.  * PUBLIC: int __ham_newpage_recover
  162.  * PUBLIC:     __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  163.  */
  164. int
  165. __ham_newpage_recover(dbenv, dbtp, lsnp, op, info)
  166. DB_ENV *dbenv;
  167. DBT *dbtp;
  168. DB_LSN *lsnp;
  169. db_recops op;
  170. void *info;
  171. {
  172. __ham_newpage_args *argp;
  173. DB *file_dbp;
  174. DBC *dbc;
  175. DB_MPOOLFILE *mpf;
  176. PAGE *pagep;
  177. int cmp_n, cmp_p, flags, getmeta, ret;
  178. COMPQUIET(info, NULL);
  179. getmeta = 0;
  180. REC_PRINT(__ham_newpage_print);
  181. REC_INTRO(__ham_newpage_read, 1);
  182. if ((ret = memp_fget(mpf, &argp->new_pgno, 0, &pagep)) != 0) {
  183. if (DB_UNDO(op)) {
  184. /*
  185.  * We are undoing and the page doesn't exist.  That
  186.  * is equivalent to having a pagelsn of 0, so we
  187.  * would not have to undo anything.  In this case,
  188.  * don't bother creating a page.
  189.  */
  190. ret = 0;
  191. goto ppage;
  192. } else if ((ret = memp_fget(mpf, &argp->new_pgno,
  193.     DB_MPOOL_CREATE, &pagep)) != 0)
  194. goto out;
  195. }
  196. if ((ret = __ham_get_meta(dbc)) != 0)
  197. goto out;
  198. getmeta = 1;
  199. /*
  200.  * There are potentially three pages we need to check: the one
  201.  * that we created/deleted, the one before it and the one after
  202.  * it.
  203.  */
  204. cmp_n = log_compare(lsnp, &LSN(pagep));
  205. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  206. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  207. flags = 0;
  208. if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) ||
  209.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) {
  210. /* Redo a create new page or undo a delete new page. */
  211. P_INIT(pagep, file_dbp->pgsize, argp->new_pgno,
  212.     argp->prev_pgno, argp->next_pgno, 0, P_HASH);
  213. flags = DB_MPOOL_DIRTY;
  214. } else if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DELOVFL) ||
  215.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) {
  216. /*
  217.  * Redo a delete or undo a create new page.  All we
  218.  * really need to do is change the LSN.
  219.  */
  220. flags = DB_MPOOL_DIRTY;
  221. }
  222. if (flags)
  223. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->pagelsn;
  224. if ((ret = memp_fput(file_dbp->mpf, pagep, flags)) != 0)
  225. goto out;
  226. /* Now do the prev page. */
  227. ppage: if (argp->prev_pgno != PGNO_INVALID) {
  228. if ((ret = memp_fget(mpf, &argp->prev_pgno, 0, &pagep)) != 0) {
  229. if (DB_UNDO(op)) {
  230. /*
  231.  * We are undoing and the page doesn't exist.
  232.  * That is equivalent to having a pagelsn of 0,
  233.  * so we would not have to undo anything.  In
  234.  * this case, don't bother creating a page.
  235.  */
  236. ret = 0;
  237. goto npage;
  238. } else if ((ret =
  239.     memp_fget(mpf, &argp->prev_pgno,
  240.     DB_MPOOL_CREATE, &pagep)) != 0)
  241. goto out;
  242. }
  243. cmp_n = log_compare(lsnp, &LSN(pagep));
  244. cmp_p = log_compare(&LSN(pagep), &argp->prevlsn);
  245. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->prevlsn);
  246. flags = 0;
  247. if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) ||
  248.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) {
  249. /* Redo a create new page or undo a delete new page. */
  250. pagep->next_pgno = argp->new_pgno;
  251. flags = DB_MPOOL_DIRTY;
  252. } else if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DELOVFL) ||
  253.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) {
  254. /* Redo a delete or undo a create new page. */
  255. pagep->next_pgno = argp->next_pgno;
  256. flags = DB_MPOOL_DIRTY;
  257. }
  258. if (flags)
  259. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->prevlsn;
  260. if ((ret = memp_fput(file_dbp->mpf, pagep, flags)) != 0)
  261. goto out;
  262. }
  263. /* Now time to do the next page */
  264. npage: if (argp->next_pgno != PGNO_INVALID) {
  265. if ((ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0) {
  266. if (DB_UNDO(op)) {
  267. /*
  268.  * We are undoing and the page doesn't exist.
  269.  * That is equivalent to having a pagelsn of 0,
  270.  * so we would not have to undo anything.  In
  271.  * this case, don't bother creating a page.
  272.  */
  273. goto done;
  274. } else if ((ret =
  275.     memp_fget(mpf, &argp->next_pgno,
  276.     DB_MPOOL_CREATE, &pagep)) != 0)
  277. goto out;
  278. }
  279. cmp_n = log_compare(lsnp, &LSN(pagep));
  280. cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
  281. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nextlsn);
  282. flags = 0;
  283. if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == PUTOVFL) ||
  284.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == DELOVFL)) {
  285. /* Redo a create new page or undo a delete new page. */
  286. pagep->prev_pgno = argp->new_pgno;
  287. flags = DB_MPOOL_DIRTY;
  288. } else if ((cmp_p == 0 && DB_REDO(op) && argp->opcode == DELOVFL) ||
  289.     (cmp_n == 0 && DB_UNDO(op) && argp->opcode == PUTOVFL)) {
  290. /* Redo a delete or undo a create new page. */
  291. pagep->prev_pgno = argp->prev_pgno;
  292. flags = DB_MPOOL_DIRTY;
  293. }
  294. if (flags)
  295. LSN(pagep) = DB_REDO(op) ? *lsnp : argp->nextlsn;
  296. if ((ret = memp_fput(file_dbp->mpf, pagep, flags)) != 0)
  297. goto out;
  298. }
  299. done: *lsnp = argp->prev_lsn;
  300. ret = 0;
  301. out: if (getmeta)
  302. (void)__ham_release_meta(dbc);
  303. REC_CLOSE;
  304. }
  305. /*
  306.  * __ham_replace_recover --
  307.  * This log message refers to partial puts that are local to a single
  308.  * page.  You can think of them as special cases of the more general
  309.  * insdel log message.
  310.  *
  311.  * PUBLIC: int __ham_replace_recover
  312.  * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  313.  */
  314. int
  315. __ham_replace_recover(dbenv, dbtp, lsnp, op, info)
  316. DB_ENV *dbenv;
  317. DBT *dbtp;
  318. DB_LSN *lsnp;
  319. db_recops op;
  320. void *info;
  321. {
  322. __ham_replace_args *argp;
  323. DB *file_dbp;
  324. DBC *dbc;
  325. DB_MPOOLFILE *mpf;
  326. DBT dbt;
  327. PAGE *pagep;
  328. int32_t grow;
  329. int cmp_n, cmp_p, flags, getmeta, ret;
  330. u_int8_t *hk;
  331. COMPQUIET(info, NULL);
  332. getmeta = 0;
  333. REC_PRINT(__ham_replace_print);
  334. REC_INTRO(__ham_replace_read, 1);
  335. if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
  336. if (DB_UNDO(op)) {
  337. /*
  338.  * We are undoing and the page doesn't exist.  That
  339.  * is equivalent to having a pagelsn of 0, so we
  340.  * would not have to undo anything.  In this case,
  341.  * don't bother creating a page.
  342.  */
  343. goto done;
  344. } else if ((ret = memp_fget(mpf, &argp->pgno,
  345.     DB_MPOOL_CREATE, &pagep)) != 0)
  346. goto out;
  347. }
  348. if ((ret = __ham_get_meta(dbc)) != 0)
  349. goto out;
  350. getmeta = 1;
  351. cmp_n = log_compare(lsnp, &LSN(pagep));
  352. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  353. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  354. memset(&dbt, 0, sizeof(dbt));
  355. flags = 0;
  356. grow = 1;
  357. if (cmp_p == 0 && DB_REDO(op)) {
  358. /* Reapply the change as specified. */
  359. dbt.data = argp->newitem.data;
  360. dbt.size = argp->newitem.size;
  361. grow = argp->newitem.size - argp->olditem.size;
  362. LSN(pagep) = *lsnp;
  363. flags = DB_MPOOL_DIRTY;
  364. } else if (cmp_n == 0 && DB_UNDO(op)) {
  365. /* Undo the already applied change. */
  366. dbt.data = argp->olditem.data;
  367. dbt.size = argp->olditem.size;
  368. grow = argp->olditem.size - argp->newitem.size;
  369. LSN(pagep) = argp->pagelsn;
  370. flags = DB_MPOOL_DIRTY;
  371. }
  372. if (flags) {
  373. __ham_onpage_replace(pagep,
  374.     file_dbp->pgsize, argp->ndx, argp->off, grow, &dbt);
  375. if (argp->makedup) {
  376. hk = P_ENTRY(pagep, argp->ndx);
  377. if (DB_REDO(op))
  378. HPAGE_PTYPE(hk) = H_DUPLICATE;
  379. else
  380. HPAGE_PTYPE(hk) = H_KEYDATA;
  381. }
  382. }
  383. if ((ret = memp_fput(file_dbp->mpf, pagep, flags)) != 0)
  384. goto out;
  385. done: *lsnp = argp->prev_lsn;
  386. ret = 0;
  387. out: if (getmeta)
  388. (void)__ham_release_meta(dbc);
  389. REC_CLOSE;
  390. }
  391. /*
  392.  * __ham_splitdata_recover --
  393.  *
  394.  * PUBLIC: int __ham_splitdata_recover
  395.  * PUBLIC:    __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  396.  */
  397. int
  398. __ham_splitdata_recover(dbenv, dbtp, lsnp, op, info)
  399. DB_ENV *dbenv;
  400. DBT *dbtp;
  401. DB_LSN *lsnp;
  402. db_recops op;
  403. void *info;
  404. {
  405. __ham_splitdata_args *argp;
  406. DB *file_dbp;
  407. DBC *dbc;
  408. DB_MPOOLFILE *mpf;
  409. PAGE *pagep;
  410. int cmp_n, cmp_p, flags, getmeta, ret;
  411. COMPQUIET(info, NULL);
  412. getmeta = 0;
  413. REC_PRINT(__ham_splitdata_print);
  414. REC_INTRO(__ham_splitdata_read, 1);
  415. if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
  416. if (DB_UNDO(op)) {
  417. /*
  418.  * We are undoing and the page doesn't exist.  That
  419.  * is equivalent to having a pagelsn of 0, so we
  420.  * would not have to undo anything.  In this case,
  421.  * don't bother creating a page.
  422.  */
  423. goto done;
  424. } else if ((ret = memp_fget(mpf, &argp->pgno,
  425.     DB_MPOOL_CREATE, &pagep)) != 0)
  426. goto out;
  427. }
  428. if ((ret = __ham_get_meta(dbc)) != 0)
  429. goto out;
  430. getmeta = 1;
  431. cmp_n = log_compare(lsnp, &LSN(pagep));
  432. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  433. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  434. /*
  435.  * There are two types of log messages here, one for the old page
  436.  * and one for the new pages created.  The original image in the
  437.  * SPLITOLD record is used for undo.  The image in the SPLITNEW
  438.  * is used for redo.  We should never have a case where there is
  439.  * a redo operation and the SPLITOLD record is on disk, but not
  440.  * the SPLITNEW record.  Therefore, we only have work to do when
  441.  * redo NEW messages and undo OLD messages, but we have to update
  442.  * LSNs in both cases.
  443.  */
  444. flags = 0;
  445. if (cmp_p == 0 && DB_REDO(op)) {
  446. if (argp->opcode == SPLITNEW)
  447. /* Need to redo the split described. */
  448. memcpy(pagep, argp->pageimage.data,
  449.     argp->pageimage.size);
  450. LSN(pagep) = *lsnp;
  451. flags = DB_MPOOL_DIRTY;
  452. } else if (cmp_n == 0 && DB_UNDO(op)) {
  453. if (argp->opcode == SPLITOLD) {
  454. /* Put back the old image. */
  455. memcpy(pagep, argp->pageimage.data,
  456.     argp->pageimage.size);
  457. } else
  458. P_INIT(pagep, file_dbp->pgsize, argp->pgno,
  459.     PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
  460. LSN(pagep) = argp->pagelsn;
  461. flags = DB_MPOOL_DIRTY;
  462. }
  463. if ((ret = memp_fput(file_dbp->mpf, pagep, flags)) != 0)
  464. goto out;
  465. done: *lsnp = argp->prev_lsn;
  466. ret = 0;
  467. out: if (getmeta)
  468. (void)__ham_release_meta(dbc);
  469. REC_CLOSE;
  470. }
  471. /*
  472.  * __ham_copypage_recover --
  473.  * Recovery function for copypage.
  474.  *
  475.  * PUBLIC: int __ham_copypage_recover
  476.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  477.  */
  478. int
  479. __ham_copypage_recover(dbenv, dbtp, lsnp, op, info)
  480. DB_ENV *dbenv;
  481. DBT *dbtp;
  482. DB_LSN *lsnp;
  483. db_recops op;
  484. void *info;
  485. {
  486. __ham_copypage_args *argp;
  487. DB *file_dbp;
  488. DBC *dbc;
  489. DB_MPOOLFILE *mpf;
  490. PAGE *pagep;
  491. int cmp_n, cmp_p, flags, getmeta, ret;
  492. COMPQUIET(info, NULL);
  493. getmeta = 0;
  494. REC_PRINT(__ham_copypage_print);
  495. REC_INTRO(__ham_copypage_read, 1);
  496. if ((ret = __ham_get_meta(dbc)) != 0)
  497. goto out;
  498. getmeta = 1;
  499. flags = 0;
  500. /* This is the bucket page. */
  501. if ((ret = memp_fget(mpf, &argp->pgno, 0, &pagep)) != 0) {
  502. if (DB_UNDO(op)) {
  503. /*
  504.  * We are undoing and the page doesn't exist.  That
  505.  * is equivalent to having a pagelsn of 0, so we
  506.  * would not have to undo anything.  In this case,
  507.  * don't bother creating a page.
  508.  */
  509. ret = 0;
  510. goto donext;
  511. } else if ((ret = memp_fget(mpf, &argp->pgno,
  512.     DB_MPOOL_CREATE, &pagep)) != 0)
  513. goto out;
  514. }
  515. cmp_n = log_compare(lsnp, &LSN(pagep));
  516. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  517. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  518. if (cmp_p == 0 && DB_REDO(op)) {
  519. /* Need to redo update described. */
  520. memcpy(pagep, argp->page.data, argp->page.size);
  521. PGNO(pagep) = argp->pgno;
  522. PREV_PGNO(pagep) = PGNO_INVALID;
  523. LSN(pagep) = *lsnp;
  524. flags = DB_MPOOL_DIRTY;
  525. } else if (cmp_n == 0 && DB_UNDO(op)) {
  526. /* Need to undo update described. */
  527. P_INIT(pagep, file_dbp->pgsize, argp->pgno, PGNO_INVALID,
  528.     argp->next_pgno, 0, P_HASH);
  529. LSN(pagep) = argp->pagelsn;
  530. flags = DB_MPOOL_DIRTY;
  531. }
  532. if ((ret = memp_fput(mpf, pagep, flags)) != 0)
  533. goto out;
  534. donext: /* Now fix up the "next" page. */
  535. if ((ret = memp_fget(mpf, &argp->next_pgno, 0, &pagep)) != 0) {
  536. if (DB_UNDO(op)) {
  537. /*
  538.  * We are undoing and the page doesn't exist.  That
  539.  * is equivalent to having a pagelsn of 0, so we
  540.  * would not have to undo anything.  In this case,
  541.  * don't bother creating a page.
  542.  */
  543. ret = 0;
  544. goto do_nn;
  545. } else if ((ret = memp_fget(mpf, &argp->next_pgno,
  546.     DB_MPOOL_CREATE, &pagep)) != 0)
  547. goto out;
  548. }
  549. /* For REDO just update the LSN. For UNDO copy page back. */
  550. cmp_n = log_compare(lsnp, &LSN(pagep));
  551. cmp_p = log_compare(&LSN(pagep), &argp->nextlsn);
  552. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nextlsn);
  553. flags = 0;
  554. if (cmp_p == 0 && DB_REDO(op)) {
  555. LSN(pagep) = *lsnp;
  556. flags = DB_MPOOL_DIRTY;
  557. } else if (cmp_n == 0 && DB_UNDO(op)) {
  558. /* Need to undo update described. */
  559. memcpy(pagep, argp->page.data, argp->page.size);
  560. flags = DB_MPOOL_DIRTY;
  561. }
  562. if ((ret = memp_fput(mpf, pagep, flags)) != 0)
  563. goto out;
  564. /* Now fix up the next's next page. */
  565. do_nn: if (argp->nnext_pgno == PGNO_INVALID)
  566. goto done;
  567. if ((ret = memp_fget(mpf, &argp->nnext_pgno, 0, &pagep)) != 0) {
  568. if (DB_UNDO(op)) {
  569. /*
  570.  * We are undoing and the page doesn't exist.  That
  571.  * is equivalent to having a pagelsn of 0, so we
  572.  * would not have to undo anything.  In this case,
  573.  * don't bother creating a page.
  574.  */
  575. goto done;
  576. } else if ((ret = memp_fget(mpf, &argp->nnext_pgno,
  577.     DB_MPOOL_CREATE, &pagep)) != 0)
  578. goto out;
  579. }
  580. cmp_n = log_compare(lsnp, &LSN(pagep));
  581. cmp_p = log_compare(&LSN(pagep), &argp->nnextlsn);
  582. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->nnextlsn);
  583. flags = 0;
  584. if (cmp_p == 0 && DB_REDO(op)) {
  585. /* Need to redo update described. */
  586. PREV_PGNO(pagep) = argp->pgno;
  587. LSN(pagep) = *lsnp;
  588. flags = DB_MPOOL_DIRTY;
  589. } else if (cmp_n == 0 && DB_UNDO(op)) {
  590. /* Need to undo update described. */
  591. PREV_PGNO(pagep) = argp->next_pgno;
  592. LSN(pagep) = argp->nnextlsn;
  593. flags = DB_MPOOL_DIRTY;
  594. }
  595. if ((ret = memp_fput(mpf, pagep, flags)) != 0)
  596. goto out;
  597. done: *lsnp = argp->prev_lsn;
  598. ret = 0;
  599. out: if (getmeta)
  600. (void)__ham_release_meta(dbc);
  601. REC_CLOSE;
  602. }
  603. /*
  604.  * __ham_metagroup_recover --
  605.  * Recovery function for metagroup.
  606.  *
  607.  * PUBLIC: int __ham_metagroup_recover
  608.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  609.  */
  610. int
  611. __ham_metagroup_recover(dbenv, dbtp, lsnp, op, info)
  612. DB_ENV *dbenv;
  613. DBT *dbtp;
  614. DB_LSN *lsnp;
  615. db_recops op;
  616. void *info;
  617. {
  618. __ham_metagroup_args *argp;
  619. HASH_CURSOR *hcp;
  620. DB *file_dbp;
  621. DBC *dbc;
  622. DB_MPOOLFILE *mpf;
  623. PAGE *pagep;
  624. db_pgno_t last_pgno;
  625. int cmp_n, cmp_p, flags, groupgrow, ret;
  626. COMPQUIET(info, NULL);
  627. REC_PRINT(__ham_metagroup_print);
  628. REC_INTRO(__ham_metagroup_read, 1);
  629. /*
  630.  * This logs the virtual create of pages pgno to pgno + bucket
  631.  * Since the mpool page-allocation is not really able to be
  632.  * transaction protected, we can never undo it.  Even in an abort,
  633.  * we have to allocate these pages to the hash table.
  634.  * The log record contains:
  635.  * bucket: new bucket being allocated.
  636.  * pgno: page number of the new bucket.
  637.  * if bucket is a power of 2, then we allocated a whole batch of
  638.  * pages; if it's not, then we simply allocated one new page.
  639.  */
  640. groupgrow =
  641.     (u_int32_t)(1 << __db_log2(argp->bucket + 1)) == argp->bucket + 1;
  642. last_pgno = argp->pgno;
  643. if (groupgrow)
  644. /* Read the last page. */
  645. last_pgno += argp->bucket;
  646. if ((ret = memp_fget(mpf, &last_pgno, DB_MPOOL_CREATE, &pagep)) != 0)
  647. goto out;
  648. cmp_n = log_compare(lsnp, &LSN(pagep));
  649. cmp_p = log_compare(&LSN(pagep), &argp->pagelsn);
  650. CHECK_LSN(op, cmp_p, &LSN(pagep), &argp->pagelsn);
  651. flags = 0;
  652. if ((cmp_p == 0 && DB_REDO(op)) || (cmp_n == 0 && DB_UNDO(op))) {
  653. /*
  654.  * We need to make sure that we redo the allocation of the
  655.  * pages.
  656.  */
  657. if (DB_REDO(op))
  658. pagep->lsn = *lsnp;
  659. else
  660. pagep->lsn = argp->pagelsn;
  661. flags = DB_MPOOL_DIRTY;
  662. }
  663. if ((ret = memp_fput(mpf, pagep, flags)) != 0)
  664. goto out;
  665. /* Now we have to update the meta-data page. */
  666. hcp = (HASH_CURSOR *)dbc->internal;
  667. if ((ret = __ham_get_meta(dbc)) != 0)
  668. goto out;
  669. cmp_n = log_compare(lsnp, &hcp->hdr->dbmeta.lsn);
  670. cmp_p = log_compare(&hcp->hdr->dbmeta.lsn, &argp->metalsn);
  671. CHECK_LSN(op, cmp_p, &hcp->hdr->dbmeta.lsn, &argp->metalsn);
  672. if ((cmp_p == 0 && DB_REDO(op)) || (cmp_n == 0 && DB_UNDO(op))) {
  673. if (DB_REDO(op)) {
  674. /* Redo the actual updating of bucket counts. */
  675. ++hcp->hdr->max_bucket;
  676. if (groupgrow) {
  677. hcp->hdr->low_mask = hcp->hdr->high_mask;
  678. hcp->hdr->high_mask =
  679.     (argp->bucket + 1) | hcp->hdr->low_mask;
  680. }
  681. hcp->hdr->dbmeta.lsn = *lsnp;
  682. } else {
  683. /* Undo the actual updating of bucket counts. */
  684. --hcp->hdr->max_bucket;
  685. if (groupgrow) {
  686. hcp->hdr->high_mask = hcp->hdr->low_mask;
  687. hcp->hdr->low_mask = hcp->hdr->high_mask >> 1;
  688. }
  689. hcp->hdr->dbmeta.lsn = argp->metalsn;
  690. }
  691. if (groupgrow &&
  692.     hcp->hdr->spares[__db_log2(argp->bucket + 1) + 1] ==
  693.     PGNO_INVALID)
  694. hcp->hdr->spares[__db_log2(argp->bucket + 1) + 1] =
  695.     argp->pgno - argp->bucket - 1;
  696. F_SET(hcp, H_DIRTY);
  697. }
  698. if ((ret = __ham_release_meta(dbc)) != 0)
  699. goto out;
  700. done: *lsnp = argp->prev_lsn;
  701. ret = 0;
  702. out: REC_CLOSE;
  703. }
  704. /*
  705.  * __ham_groupalloc_recover --
  706.  * Recover the batch creation of a set of pages for a new database.
  707.  *
  708.  * PUBLIC: int __ham_groupalloc_recover
  709.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  710.  */
  711. int
  712. __ham_groupalloc_recover(dbenv, dbtp, lsnp, op, info)
  713. DB_ENV *dbenv;
  714. DBT *dbtp;
  715. DB_LSN *lsnp;
  716. db_recops op;
  717. void *info;
  718. {
  719. __ham_groupalloc_args *argp;
  720. DBMETA *mmeta;
  721. DB_MPOOLFILE *mpf;
  722. DB *file_dbp;
  723. DBC *dbc;
  724. db_pgno_t pgno;
  725. int cmp_n, cmp_p, flags, ret;
  726. REC_PRINT(__ham_groupalloc_print);
  727. REC_INTRO(__ham_groupalloc_read, 0);
  728. pgno = PGNO_BASE_MD;
  729. if ((ret = memp_fget(mpf, &pgno, 0, &mmeta)) != 0) {
  730. if (DB_REDO(op)) {
  731. /* Page should have existed. */
  732. (void)__db_pgerr(file_dbp, pgno);
  733. goto out;
  734. } else {
  735. ret = 0;
  736. goto done;
  737. }
  738. }
  739. cmp_n = log_compare(lsnp, &LSN(mmeta));
  740. cmp_p = log_compare(&LSN(mmeta), &argp->meta_lsn);
  741. CHECK_LSN(op, cmp_p, &LSN(mmeta), &argp->meta_lsn);
  742. /*
  743.  * Basically, we used mpool to allocate a chunk of pages.
  744.  * We need to either add those to a free list (in the undo
  745.  * case) or initialize them (in the redo case).
  746.  *
  747.  * If we are redoing and this is a hash subdatabase, it's possible
  748.  * that the pages were never allocated, so we'd better check for
  749.  * that and handle it here.
  750.  */
  751. flags = 0;
  752. if (DB_REDO(op)) {
  753. if ((ret = __ham_alloc_pages(file_dbp, argp)) != 0)
  754. goto out1;
  755. if (cmp_p == 0) {
  756. LSN(mmeta) = *lsnp;
  757. flags = DB_MPOOL_DIRTY;
  758. }
  759. }
  760. /*
  761.  * Always put the pages into the limbo list and free them later.
  762.  */
  763. else if (DB_UNDO(op)) {
  764. if ((ret = __db_add_limbo(dbenv,
  765.     info, argp->fileid, argp->start_pgno, argp->num)) != 0)
  766. goto out;
  767. if (cmp_n == 0) {
  768. LSN(mmeta) = argp->meta_lsn;
  769. flags = DB_MPOOL_DIRTY;
  770. }
  771. }
  772. out1: if ((ret = memp_fput(mpf, mmeta, flags)) != 0)
  773. goto out;
  774. done: if (ret == 0)
  775. *lsnp = argp->prev_lsn;
  776. out: REC_CLOSE;
  777. }
  778. /*
  779.  * __ham_alloc_pages --
  780.  *
  781.  * Called during redo of a file create.  We create new pages in the file
  782.  * using the MPOOL_NEW_GROUP flag.  We then log the meta-data page with a
  783.  * __crdel_metasub message.  If we manage to crash without the newly written
  784.  * pages getting to disk (I'm not sure this can happen anywhere except our
  785.  * test suite?!), then we need to go through a recreate the final pages.
  786.  * Hash normally has holes in its files and handles them appropriately.
  787.  */
  788. static int
  789. __ham_alloc_pages(dbp, argp)
  790. DB *dbp;
  791. __ham_groupalloc_args *argp;
  792. {
  793. DB_MPOOLFILE *mpf;
  794. PAGE *pagep;
  795. db_pgno_t pgno;
  796. int ret;
  797. mpf = dbp->mpf;
  798. /* Read the last page of the allocation. */
  799. pgno = argp->start_pgno + argp->num - 1;
  800. /* If the page exists, and it has been initialized, then we're done. */
  801. if ((ret = memp_fget(mpf, &pgno, 0, &pagep)) == 0) {
  802. if ((pagep->type == P_INVALID) && IS_ZERO_LSN(pagep->lsn))
  803. goto reinit_page;
  804. if ((ret = memp_fput(mpf, pagep, 0)) != 0)
  805. return (ret);
  806. return (0);
  807. }
  808. /*
  809.  * Had to create the page.  On some systems (read "Windows"),
  810.  * you can find random garbage on pages to which you haven't
  811.  * yet written.  So, we have an os layer that will do the
  812.  * right thing for group allocations.  We call that directly
  813.  * to make sure all the pages are allocated and then continue
  814.  * merrily on our way with normal recovery.
  815.  */
  816. if ((ret = __os_fpinit(dbp->dbenv, &mpf->fh,
  817.     argp->start_pgno, argp->num, dbp->pgsize)) != 0)
  818. return (ret);
  819. if ((ret = memp_fget(mpf, &pgno, DB_MPOOL_CREATE, &pagep)) != 0) {
  820. (void)__db_pgerr(dbp, pgno);
  821. return (ret);
  822. }
  823. reinit_page:
  824. /* Initialize the newly allocated page. */
  825. P_INIT(pagep,
  826.     dbp->pgsize, pgno, PGNO_INVALID, PGNO_INVALID, 0, P_HASH);
  827. ZERO_LSN(pagep->lsn);
  828. if ((ret = memp_fput(mpf, pagep, DB_MPOOL_DIRTY)) != 0)
  829. return (ret);
  830. return (0);
  831. }
  832. /*
  833.  * __ham_curadj_recover --
  834.  * Undo cursor adjustments if a subtransaction fails.
  835.  *
  836.  * PUBLIC: int __ham_curadj_recover
  837.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  838.  */
  839. int
  840. __ham_curadj_recover(dbenv, dbtp, lsnp, op, info)
  841. DB_ENV *dbenv;
  842. DBT *dbtp;
  843. DB_LSN *lsnp;
  844. db_recops op;
  845. void *info;
  846. {
  847. __ham_curadj_args *argp;
  848. DB_MPOOLFILE *mpf;
  849. DB *file_dbp;
  850. DBC *dbc;
  851. int ret;
  852. HASH_CURSOR *hcp;
  853. REC_PRINT(__ham_groupalloc_print);
  854. ret = 0;
  855. if (op != DB_TXN_ABORT)
  856. goto done;
  857. REC_INTRO(__ham_curadj_read, 0);
  858. COMPQUIET(info, NULL);
  859. /*
  860.  * Undo the adjustment by reinitializing the the cursor
  861.  * to look like the one that was used to do the adustment,
  862.  * then we invert the add so that undo the adjustment.
  863.  */
  864. hcp = (HASH_CURSOR *)dbc->internal;
  865. hcp->pgno = argp->pgno;
  866. hcp->indx = argp->indx;
  867. hcp->dup_off = argp->dup_off;
  868. hcp->order = argp->order;
  869. if (!argp->add)
  870. F_SET(hcp, H_DELETED);
  871. (void)__ham_c_update(dbc, argp->len, !argp->add, argp->is_dup);
  872. done: *lsnp = argp->prev_lsn;
  873. out: REC_CLOSE;
  874. }
  875. /*
  876.  * __ham_chgpg_recover --
  877.  * Undo cursor adjustments if a subtransaction fails.
  878.  *
  879.  * PUBLIC: int __ham_chgpg_recover
  880.  * PUBLIC:   __P((DB_ENV *, DBT *, DB_LSN *, db_recops, void *));
  881.  */
  882. int
  883. __ham_chgpg_recover(dbenv, dbtp, lsnp, op, info)
  884. DB_ENV *dbenv;
  885. DBT *dbtp;
  886. DB_LSN *lsnp;
  887. db_recops op;
  888. void *info;
  889. {
  890. __ham_chgpg_args *argp;
  891. BTREE_CURSOR *opdcp;
  892. DB_MPOOLFILE *mpf;
  893. DB *file_dbp, *ldbp;
  894. DBC *dbc;
  895. int ret;
  896. DBC *cp;
  897. HASH_CURSOR *lcp;
  898. REC_PRINT(__ham_chgpg_print);
  899. ret = 0;
  900. if (op != DB_TXN_ABORT)
  901. goto out;
  902. REC_INTRO(__ham_chgpg_read, 0);
  903. COMPQUIET(info, NULL);
  904. MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
  905. for (ldbp = __dblist_get(dbenv, file_dbp->adj_fileid);
  906.     ldbp != NULL && ldbp->adj_fileid == file_dbp->adj_fileid;
  907.     ldbp = LIST_NEXT(ldbp, dblistlinks)) {
  908. MUTEX_THREAD_LOCK(dbenv, file_dbp->mutexp);
  909. for (cp = TAILQ_FIRST(&ldbp->active_queue); cp != NULL;
  910.     cp = TAILQ_NEXT(cp, links)) {
  911. lcp = (HASH_CURSOR *)cp->internal;
  912. switch (argp->mode) {
  913. case DB_HAM_CHGPG:
  914. if (lcp->pgno != argp->new_pgno)
  915. break;
  916. if (argp->old_indx == NDX_INVALID)
  917. lcp->pgno = argp->old_pgno;
  918. else if (lcp->indx == argp->new_indx) {
  919. lcp->indx = argp->old_indx;
  920. lcp->pgno = argp->old_pgno;
  921. }
  922. break;
  923. case DB_HAM_SPLIT:
  924. if (lcp->pgno == argp->new_pgno
  925.      && lcp->indx == argp->new_indx) {
  926. lcp->indx = argp->old_indx;
  927. lcp->pgno = argp->old_pgno;
  928. }
  929. break;
  930. case DB_HAM_DUP:
  931. if (lcp->opd != NULL) {
  932. opdcp =
  933.     (BTREE_CURSOR *)lcp->opd->internal;
  934. if (opdcp->pgno == argp->new_pgno &&
  935.      opdcp->indx == argp->new_indx) {
  936. if (F_ISSET(opdcp, C_DELETED))
  937. F_SET(lcp, H_DELETED);
  938. if ((ret =
  939.     lcp->opd->c_close(
  940.     lcp->opd)) != 0)
  941. goto out;
  942. lcp->opd = NULL;
  943. }
  944. }
  945. break;
  946. }
  947. }
  948. MUTEX_THREAD_UNLOCK(dbenv, file_dbp->mutexp);
  949. }
  950. MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
  951. done: *lsnp = argp->prev_lsn;
  952. ret = 0;
  953. out: REC_CLOSE;
  954. }