00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045 #include "db_config.h"
00046
00047 #ifndef NO_SYSTEM_INCLUDES
00048 #include <sys/types.h>
00049
00050 #include <string.h>
00051 #endif
00052
00053 #include "db_int.h"
00054 #include "dbinc/db_page.h"
00055 #include "dbinc/db_shash.h"
00056 #include "dbinc/btree.h"
00057 #include "dbinc/lock.h"
00058 #include "dbinc/mp.h"
00059
00060
00061
00062
00063
00064
00065
00066 int
00067 __bam_ditem(dbc, h, indx)
00068 DBC *dbc;
00069 PAGE *h;
00070 u_int32_t indx;
00071 {
00072 BINTERNAL *bi;
00073 BKEYDATA *bk;
00074 DB *dbp;
00075 DB_MPOOLFILE *mpf;
00076 u_int32_t nbytes;
00077 int ret;
00078 db_indx_t *inp;
00079
00080 dbp = dbc->dbp;
00081 mpf = dbp->mpf;
00082 inp = P_INP(dbp, h);
00083
00084 switch (TYPE(h)) {
00085 case P_IBTREE:
00086 bi = GET_BINTERNAL(dbp, h, indx);
00087 switch (B_TYPE(bi->type)) {
00088 case B_DUPLICATE:
00089 case B_KEYDATA:
00090 nbytes = BINTERNAL_SIZE(bi->len);
00091 break;
00092 case B_OVERFLOW:
00093 nbytes = BINTERNAL_SIZE(bi->len);
00094 if ((ret =
00095 __db_doff(dbc, ((BOVERFLOW *)bi->data)->pgno)) != 0)
00096 return (ret);
00097 break;
00098 default:
00099 return (__db_pgfmt(dbp->dbenv, PGNO(h)));
00100 }
00101 break;
00102 case P_IRECNO:
00103 nbytes = RINTERNAL_SIZE;
00104 break;
00105 case P_LBTREE:
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115 if ((indx % 2) == 0) {
00116
00117
00118
00119
00120
00121
00122 if (indx + P_INDX < (u_int32_t)NUM_ENT(h) &&
00123 inp[indx] == inp[indx + P_INDX])
00124 return (__bam_adjindx(dbc,
00125 h, indx, indx + O_INDX, 0));
00126
00127
00128
00129
00130
00131 if (indx > 0 && inp[indx] == inp[indx - P_INDX])
00132 return (__bam_adjindx(dbc,
00133 h, indx, indx - P_INDX, 0));
00134 }
00135
00136 case P_LDUP:
00137 case P_LRECNO:
00138 bk = GET_BKEYDATA(dbp, h, indx);
00139 switch (B_TYPE(bk->type)) {
00140 case B_DUPLICATE:
00141 nbytes = BOVERFLOW_SIZE;
00142 break;
00143 case B_OVERFLOW:
00144 nbytes = BOVERFLOW_SIZE;
00145 if ((ret = __db_doff(
00146 dbc, (GET_BOVERFLOW(dbp, h, indx))->pgno)) != 0)
00147 return (ret);
00148 break;
00149 case B_KEYDATA:
00150 nbytes = BKEYDATA_SIZE(bk->len);
00151 break;
00152 default:
00153 return (__db_pgfmt(dbp->dbenv, PGNO(h)));
00154 }
00155 break;
00156 default:
00157 return (__db_pgfmt(dbp->dbenv, PGNO(h)));
00158 }
00159
00160
00161 if ((ret = __db_ditem(dbc, h, indx, nbytes)) != 0)
00162 return (ret);
00163 if ((ret = __memp_fset(mpf, h, DB_MPOOL_DIRTY)) != 0)
00164 return (ret);
00165
00166 return (0);
00167 }
00168
00169
00170
00171
00172
00173
00174
00175 int
00176 __bam_adjindx(dbc, h, indx, indx_copy, is_insert)
00177 DBC *dbc;
00178 PAGE *h;
00179 u_int32_t indx, indx_copy;
00180 int is_insert;
00181 {
00182 DB *dbp;
00183 DB_MPOOLFILE *mpf;
00184 db_indx_t copy, *inp;
00185 int ret;
00186
00187 dbp = dbc->dbp;
00188 mpf = dbp->mpf;
00189 inp = P_INP(dbp, h);
00190
00191
00192 if (DBC_LOGGING(dbc)) {
00193 if ((ret = __bam_adj_log(dbp, dbc->txn, &LSN(h), 0,
00194 PGNO(h), &LSN(h), indx, indx_copy, (u_int32_t)is_insert)) != 0)
00195 return (ret);
00196 } else
00197 LSN_NOT_LOGGED(LSN(h));
00198
00199
00200 if (is_insert) {
00201 copy = inp[indx_copy];
00202 if (indx != NUM_ENT(h))
00203 memmove(&inp[indx + O_INDX], &inp[indx],
00204 sizeof(db_indx_t) * (NUM_ENT(h) - indx));
00205 inp[indx] = copy;
00206 ++NUM_ENT(h);
00207 } else {
00208 --NUM_ENT(h);
00209 if (indx != NUM_ENT(h))
00210 memmove(&inp[indx], &inp[indx + O_INDX],
00211 sizeof(db_indx_t) * (NUM_ENT(h) - indx));
00212 }
00213 if ((ret = __memp_fset(mpf, h, DB_MPOOL_DIRTY)) != 0)
00214 return (ret);
00215
00216 return (0);
00217 }
00218
00219
00220
00221
00222
00223
00224
00225 int
00226 __bam_dpages(dbc, use_top, update)
00227 DBC *dbc;
00228 int use_top;
00229 int update;
00230 {
00231 BTREE_CURSOR *cp;
00232 BINTERNAL *bi;
00233 DB *dbp;
00234 DBT a, b;
00235 DB_LOCK c_lock, p_lock;
00236 DB_MPOOLFILE *mpf;
00237 EPG *epg, *save_sp, *stack_epg;
00238 PAGE *child, *parent;
00239 db_indx_t nitems;
00240 db_pgno_t pgno, root_pgno;
00241 db_recno_t rcnt;
00242 int done, ret, t_ret;
00243
00244 dbp = dbc->dbp;
00245 mpf = dbp->mpf;
00246 cp = (BTREE_CURSOR *)dbc->internal;
00247 nitems = 0;
00248 pgno = PGNO_INVALID;
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260 ret = 0;
00261 if (use_top)
00262 stack_epg = cp->sp;
00263 else
00264 for (stack_epg = cp->csp; stack_epg > cp->sp; --stack_epg)
00265 if (NUM_ENT(stack_epg->page) > 1)
00266 break;
00267 epg = stack_epg;
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 if (LEVEL(cp->csp->page) == 1 &&
00278 (ret = __bam_relink(dbc, cp->csp->page, PGNO_INVALID)) != 0)
00279 goto discard;
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289 if ((ret = __bam_ditem(dbc, epg->page, epg->indx)) != 0)
00290 goto discard;
00291 if ((ret = __bam_ca_di(dbc, PGNO(epg->page), epg->indx, -1)) != 0)
00292 goto discard;
00293
00294 if (update && epg->indx == 0) {
00295 save_sp = cp->csp;
00296 cp->csp = epg;
00297 ret = __bam_pupdate(dbc, epg->page);
00298 cp->csp = save_sp;
00299 if (ret != 0)
00300 goto discard;
00301 }
00302
00303 pgno = PGNO(epg->page);
00304 nitems = NUM_ENT(epg->page);
00305
00306 ret = __memp_fput(mpf, epg->page, 0);
00307 if ((t_ret = __TLPUT(dbc, epg->lock)) != 0 && ret == 0)
00308 ret = t_ret;
00309 if (ret != 0)
00310 goto err_inc;
00311
00312
00313 discard: for (epg = cp->sp; epg < stack_epg; ++epg) {
00314 if ((t_ret = __memp_fput(mpf, epg->page, 0)) != 0 && ret == 0)
00315 ret = t_ret;
00316 epg->page = NULL;
00317 if ((t_ret = __TLPUT(dbc, epg->lock)) != 0 && ret == 0)
00318 ret = t_ret;
00319 }
00320 if (ret != 0)
00321 goto err;
00322
00323
00324 while (++epg <= cp->csp) {
00325
00326
00327
00328
00329
00330
00331 if (NUM_ENT(epg->page) != 0) {
00332 DB_ASSERT(LEVEL(epg->page) != 1);
00333
00334 if ((ret = __bam_ditem(dbc, epg->page, epg->indx)) != 0)
00335 goto err;
00336
00337
00338
00339
00340
00341
00342
00343 if (NUM_ENT(epg->page) != 0)
00344 goto err;
00345 }
00346
00347 ret = __db_free(dbc, epg->page);
00348 if (cp->page == epg->page)
00349 cp->page = NULL;
00350 epg->page = NULL;
00351 if ((t_ret = __TLPUT(dbc, epg->lock)) != 0 && ret == 0)
00352 ret = t_ret;
00353 if (ret != 0)
00354 goto err_inc;
00355 }
00356
00357 if (0) {
00358 err_inc: ++epg;
00359 err: for (; epg <= cp->csp; ++epg) {
00360 if (epg->page != NULL)
00361 (void)__memp_fput(mpf, epg->page, 0);
00362 (void)__TLPUT(dbc, epg->lock);
00363 }
00364 BT_STK_CLR(cp);
00365 return (ret);
00366 }
00367 BT_STK_CLR(cp);
00368
00369
00370
00371
00372
00373
00374
00375 root_pgno = cp->root;
00376 if (pgno != root_pgno || nitems != 1)
00377 return (0);
00378
00379 for (done = 0; !done;) {
00380
00381 parent = child = NULL;
00382 LOCK_INIT(p_lock);
00383 LOCK_INIT(c_lock);
00384
00385
00386 pgno = root_pgno;
00387 if ((ret =
00388 __db_lget(dbc, 0, pgno, DB_LOCK_WRITE, 0, &p_lock)) != 0)
00389 goto stop;
00390 if ((ret = __memp_fget(mpf, &pgno, 0, &parent)) != 0)
00391 goto stop;
00392
00393 if (NUM_ENT(parent) != 1)
00394 goto stop;
00395
00396 switch (TYPE(parent)) {
00397 case P_IBTREE:
00398
00399
00400
00401
00402 bi = GET_BINTERNAL(dbp, parent, 0);
00403 if (B_TYPE(bi->type) == B_OVERFLOW)
00404 if ((ret = __db_doff(dbc,
00405 ((BOVERFLOW *)bi->data)->pgno)) != 0)
00406 goto stop;
00407 pgno = bi->pgno;
00408 break;
00409 case P_IRECNO:
00410 pgno = GET_RINTERNAL(dbp, parent, 0)->pgno;
00411 break;
00412 default:
00413 goto stop;
00414 }
00415
00416
00417 if ((ret =
00418 __db_lget(dbc, 0, pgno, DB_LOCK_WRITE, 0, &c_lock)) != 0)
00419 goto stop;
00420 if ((ret = __memp_fget(mpf, &pgno, 0, &child)) != 0)
00421 goto stop;
00422
00423
00424 if (DBC_LOGGING(dbc)) {
00425 memset(&a, 0, sizeof(a));
00426 a.data = child;
00427 a.size = dbp->pgsize;
00428 memset(&b, 0, sizeof(b));
00429 b.data = P_ENTRY(dbp, parent, 0);
00430 b.size = TYPE(parent) == P_IRECNO ? RINTERNAL_SIZE :
00431 BINTERNAL_SIZE(((BINTERNAL *)b.data)->len);
00432 if ((ret = __bam_rsplit_log(dbp, dbc->txn,
00433 &child->lsn, 0, PGNO(child), &a, PGNO(parent),
00434 RE_NREC(parent), &b, &parent->lsn)) != 0)
00435 goto stop;
00436 } else
00437 LSN_NOT_LOGGED(child->lsn);
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450 COMPQUIET(rcnt, 0);
00451 if (F_ISSET(cp, C_RECNUM) && LEVEL(child) > LEAFLEVEL)
00452 rcnt = RE_NREC(parent);
00453 memcpy(parent, child, dbp->pgsize);
00454 PGNO(parent) = root_pgno;
00455 if (F_ISSET(cp, C_RECNUM) && LEVEL(child) > LEAFLEVEL)
00456 RE_NREC_SET(parent, rcnt);
00457
00458
00459 if ((ret = __memp_fset(mpf, parent, DB_MPOOL_DIRTY)) != 0)
00460 goto stop;
00461 if ((ret = __memp_fset(mpf, child, DB_MPOOL_DIRTY)) != 0)
00462 goto stop;
00463
00464
00465 if ((ret = __bam_ca_rsplit(dbc, PGNO(child), root_pgno)) != 0)
00466 goto stop;
00467
00468
00469
00470
00471
00472
00473 if ((ret = __db_free(dbc, child)) != 0) {
00474 child = NULL;
00475 goto stop;
00476 }
00477 child = NULL;
00478
00479 if (0) {
00480 stop: done = 1;
00481 }
00482 if ((t_ret = __TLPUT(dbc, p_lock)) != 0 && ret == 0)
00483 ret = t_ret;
00484 if (parent != NULL &&
00485 (t_ret = __memp_fput(mpf, parent, 0)) != 0 && ret == 0)
00486 ret = t_ret;
00487 if ((t_ret = __TLPUT(dbc, c_lock)) != 0 && ret == 0)
00488 ret = t_ret;
00489 if (child != NULL &&
00490 (t_ret = __memp_fput(mpf, child, 0)) != 0 && ret == 0)
00491 ret = t_ret;
00492 }
00493
00494 return (ret);
00495 }
00496
00497
00498
00499
00500
00501
00502
00503 int
00504 __bam_relink(dbc, pagep, new_pgno)
00505 DBC *dbc;
00506 PAGE *pagep;
00507 db_pgno_t new_pgno;
00508 {
00509 DB *dbp;
00510 PAGE *np, *pp;
00511 DB_LOCK npl, ppl;
00512 DB_LSN *nlsnp, *plsnp, ret_lsn;
00513 DB_MPOOLFILE *mpf;
00514 int ret, t_ret;
00515
00516 dbp = dbc->dbp;
00517 np = pp = NULL;
00518 LOCK_INIT(npl);
00519 LOCK_INIT(ppl);
00520 nlsnp = plsnp = NULL;
00521 mpf = dbp->mpf;
00522 ret = 0;
00523
00524
00525
00526
00527
00528
00529 if (pagep->next_pgno != PGNO_INVALID) {
00530 if ((ret = __db_lget(dbc,
00531 0, pagep->next_pgno, DB_LOCK_WRITE, 0, &npl)) != 0)
00532 goto err;
00533 if ((ret = __memp_fget(mpf, &pagep->next_pgno, 0, &np)) != 0) {
00534 ret = __db_pgerr(dbp, pagep->next_pgno, ret);
00535 goto err;
00536 }
00537 nlsnp = &np->lsn;
00538 }
00539 if (pagep->prev_pgno != PGNO_INVALID) {
00540 if ((ret = __db_lget(dbc,
00541 0, pagep->prev_pgno, DB_LOCK_WRITE, 0, &ppl)) != 0)
00542 goto err;
00543 if ((ret = __memp_fget(mpf, &pagep->prev_pgno, 0, &pp)) != 0) {
00544 ret = __db_pgerr(dbp, pagep->prev_pgno, ret);
00545 goto err;
00546 }
00547 plsnp = &pp->lsn;
00548 }
00549
00550
00551 if (DBC_LOGGING(dbc)) {
00552 if ((ret = __bam_relink_log(dbp, dbc->txn, &ret_lsn, 0,
00553 pagep->pgno, new_pgno, pagep->prev_pgno, plsnp,
00554 pagep->next_pgno, nlsnp)) != 0)
00555 goto err;
00556 } else
00557 LSN_NOT_LOGGED(ret_lsn);
00558 if (np != NULL)
00559 np->lsn = ret_lsn;
00560 if (pp != NULL)
00561 pp->lsn = ret_lsn;
00562
00563
00564
00565
00566 if (np != NULL) {
00567 if (new_pgno == PGNO_INVALID)
00568 np->prev_pgno = pagep->prev_pgno;
00569 else
00570 np->prev_pgno = new_pgno;
00571 ret = __memp_fput(mpf, np, DB_MPOOL_DIRTY);
00572 if ((t_ret = __TLPUT(dbc, npl)) != 0 && ret == 0)
00573 ret = t_ret;
00574 if (ret != 0)
00575 goto err;
00576 }
00577
00578 if (pp != NULL) {
00579 if (new_pgno == PGNO_INVALID)
00580 pp->next_pgno = pagep->next_pgno;
00581 else
00582 pp->next_pgno = new_pgno;
00583 ret = __memp_fput(mpf, pp, DB_MPOOL_DIRTY);
00584 if ((t_ret = __TLPUT(dbc, ppl)) != 0 && ret == 0)
00585 ret = t_ret;
00586 if (ret != 0)
00587 goto err;
00588 }
00589 return (0);
00590
00591 err: if (np != NULL)
00592 (void)__memp_fput(mpf, np, 0);
00593 (void)__TLPUT(dbc, npl);
00594 if (pp != NULL)
00595 (void)__memp_fput(mpf, pp, 0);
00596 (void)__TLPUT(dbc, ppl);
00597 return (ret);
00598 }
00599
00600
00601
00602
00603
00604
00605
00606 int
00607 __bam_pupdate(dbc, lpg)
00608 DBC *dbc;
00609 PAGE *lpg;
00610 {
00611 BTREE_CURSOR *cp;
00612 DB_ENV *dbenv;
00613 EPG *epg;
00614 int ret;
00615
00616 dbenv = dbc->dbp->dbenv;
00617 cp = (BTREE_CURSOR *)dbc->internal;
00618 ret = 0;
00619
00620
00621
00622
00623
00624
00625
00626 for (epg = &cp->csp[-1]; epg >= cp->sp; epg--) {
00627 if ((ret = __bam_ditem(dbc, epg->page, epg->indx)) != 0)
00628 return (ret);
00629 epg->indx--;
00630 if ((ret = __bam_pinsert(dbc, epg,
00631 lpg, epg[1].page, BPI_NORECNUM)) != 0) {
00632 if (ret == DB_NEEDSPLIT) {
00633
00634 __db_err(dbenv,
00635 "Not enough room in parent: %s: page %lu",
00636 dbc->dbp->fname, (u_long)PGNO(epg->page));
00637 ret = __db_panic(dbenv, EINVAL);
00638 }
00639 return (ret);
00640 }
00641 }
00642 return (ret);
00643 }