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
00067 int
00068 __bam_get_root(dbc, pg, slevel, flags, stack)
00069 DBC *dbc;
00070 db_pgno_t pg;
00071 int slevel;
00072 u_int32_t flags;
00073 int *stack;
00074 {
00075 BTREE_CURSOR *cp;
00076 DB *dbp;
00077 DB_LOCK lock;
00078 DB_MPOOLFILE *mpf;
00079 PAGE *h;
00080 db_lockmode_t lock_mode;
00081 int ret, t_ret;
00082
00083 dbp = dbc->dbp;
00084 mpf = dbp->mpf;
00085 cp = (BTREE_CURSOR *)dbc->internal;
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095 try_again:
00096 *stack = LF_ISSET(S_STACK) &&
00097 (dbc->dbtype == DB_RECNO || F_ISSET(cp, C_RECNUM));
00098 lock_mode = DB_LOCK_READ;
00099 if (*stack ||
00100 LF_ISSET(S_DEL) || (LF_ISSET(S_NEXT) && LF_ISSET(S_WRITE)))
00101 lock_mode = DB_LOCK_WRITE;
00102 if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
00103 return (ret);
00104 if ((ret = __memp_fget(mpf, &pg, 0, &h)) != 0) {
00105
00106 (void)__LPUT(dbc, lock);
00107 return (ret);
00108 }
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 if (!*stack &&
00119 ((LF_ISSET(S_PARENT) && (u_int8_t)(slevel + 1) >= LEVEL(h)) ||
00120 (LF_ISSET(S_WRITE) && LEVEL(h) == LEAFLEVEL) ||
00121 (LF_ISSET(S_START) && slevel == LEVEL(h)))) {
00122 if (!STD_LOCKING(dbc))
00123 goto no_relock;
00124 ret = __memp_fput(mpf, h, 0);
00125 if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
00126 ret = t_ret;
00127 if (ret != 0)
00128 return (ret);
00129 lock_mode = DB_LOCK_WRITE;
00130 if ((ret = __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
00131 return (ret);
00132 if ((ret = __memp_fget(mpf, &pg, 0, &h)) != 0) {
00133
00134 (void)__LPUT(dbc, lock);
00135 return (ret);
00136 }
00137 if (!((LF_ISSET(S_PARENT) &&
00138 (u_int8_t)(slevel + 1) >= LEVEL(h)) ||
00139 (LF_ISSET(S_WRITE) && LEVEL(h) == LEAFLEVEL) ||
00140 (LF_ISSET(S_START) && slevel == LEVEL(h)))) {
00141
00142 ret = __memp_fput(mpf, h, 0);
00143 if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
00144 ret = t_ret;
00145 if (ret != 0)
00146 return (ret);
00147 goto try_again;
00148 }
00149 no_relock: *stack = 1;
00150 }
00151 BT_STK_ENTER(dbp->dbenv, cp, h, 0, lock, lock_mode, ret);
00152
00153 return (ret);
00154 }
00155
00156
00157
00158
00159
00160
00161
00162
00163 int
00164 __bam_search(dbc, root_pgno, key, flags, slevel, recnop, exactp)
00165 DBC *dbc;
00166 db_pgno_t root_pgno;
00167 const DBT *key;
00168 u_int32_t flags;
00169 int slevel, *exactp;
00170 db_recno_t *recnop;
00171 {
00172 BTREE *t;
00173 BTREE_CURSOR *cp;
00174 DB *dbp;
00175 DB_LOCK lock;
00176 DB_MPOOLFILE *mpf;
00177 PAGE *h;
00178 db_indx_t base, i, indx, *inp, lim;
00179 db_lockmode_t lock_mode;
00180 db_pgno_t pg;
00181 db_recno_t recno;
00182 int adjust, cmp, deloffset, ret, stack, t_ret;
00183 int (*func) __P((DB *, const DBT *, const DBT *));
00184
00185 dbp = dbc->dbp;
00186 mpf = dbp->mpf;
00187 cp = (BTREE_CURSOR *)dbc->internal;
00188 h = NULL;
00189 t = dbp->bt_internal;
00190 recno = 0;
00191
00192 BT_STK_CLR(cp);
00193
00194
00195
00196
00197
00198
00199
00200
00201
00202
00203 if (root_pgno == PGNO_INVALID)
00204 root_pgno = cp->root;
00205 if ((ret = __bam_get_root(dbc, root_pgno, slevel, flags, &stack)) != 0)
00206 return (ret);
00207 lock_mode = cp->csp->lock_mode;
00208 lock = cp->csp->lock;
00209 h = cp->csp->page;
00210
00211 BT_STK_CLR(cp);
00212
00213
00214 func = F_ISSET(dbc, DBC_OPD) ?
00215 (dbp->dup_compare == NULL ? __bam_defcmp : dbp->dup_compare) :
00216 t->bt_compare;
00217
00218 for (;;) {
00219 inp = P_INP(dbp, h);
00220 adjust = TYPE(h) == P_LBTREE ? P_INDX : O_INDX;
00221 if (LF_ISSET(S_MIN | S_MAX)) {
00222 if (LF_ISSET(S_MIN) || NUM_ENT(h) == 0)
00223 indx = 0;
00224 else if (TYPE(h) == P_LBTREE)
00225 indx = NUM_ENT(h) - 2;
00226 else
00227 indx = NUM_ENT(h) - 1;
00228
00229 if (LEVEL(h) == LEAFLEVEL ||
00230 (!LF_ISSET(S_START) && LEVEL(h) == slevel)) {
00231 if (LF_ISSET(S_NEXT))
00232 goto get_next;
00233 goto found;
00234 }
00235 goto next;
00236 }
00237
00238
00239
00240
00241
00242
00243
00244 for (base = 0,
00245 lim = NUM_ENT(h) / (db_indx_t)adjust; lim != 0; lim >>= 1) {
00246 indx = base + ((lim >> 1) * adjust);
00247 if ((ret =
00248 __bam_cmp(dbp, key, h, indx, func, &cmp)) != 0)
00249 goto err;
00250 if (cmp == 0) {
00251 if (LEVEL(h) == LEAFLEVEL ||
00252 (!LF_ISSET(S_START) &&
00253 LEVEL(h) == slevel)) {
00254 if (LF_ISSET(S_NEXT))
00255 goto get_next;
00256 goto found;
00257 }
00258 goto next;
00259 }
00260 if (cmp > 0) {
00261 base = indx + adjust;
00262 --lim;
00263 }
00264 }
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274 if (LEVEL(h) == LEAFLEVEL ||
00275 (!LF_ISSET(S_START) && LEVEL(h) == slevel)) {
00276 *exactp = 0;
00277
00278 if (LF_ISSET(S_EXACT)) {
00279 ret = DB_NOTFOUND;
00280 goto err;
00281 }
00282
00283 if (LF_ISSET(S_STK_ONLY)) {
00284 BT_STK_NUM(dbp->dbenv, cp, h, base, ret);
00285 if ((t_ret =
00286 __LPUT(dbc, lock)) != 0 && ret == 0)
00287 ret = t_ret;
00288 if ((t_ret =
00289 __memp_fput(mpf, h, 0)) != 0 && ret == 0)
00290 ret = t_ret;
00291 return (ret);
00292 }
00293 if (LF_ISSET(S_NEXT)) {
00294 get_next:
00295
00296
00297
00298 if (PGNO(h) == root_pgno) {
00299 ret = DB_NOTFOUND;
00300 goto err;
00301 }
00302
00303
00304
00305
00306
00307
00308 if ((ret = __LPUT(dbc, lock)) != 0)
00309 goto err;
00310 if ((ret = __memp_fput(mpf, h, 0)) != 0)
00311 goto err;
00312 h = NULL;
00313 LF_SET(S_MIN);
00314 LF_CLR(S_NEXT);
00315 indx = cp->sp->indx + 1;
00316 if (indx == NUM_ENT(cp->sp->page)) {
00317 ret = DB_NOTFOUND;
00318 cp->csp++;
00319 goto err;
00320 }
00321 h = cp->sp->page;
00322 cp->sp->page = NULL;
00323 lock = cp->sp->lock;
00324 LOCK_INIT(cp->sp->lock);
00325 if ((ret = __bam_stkrel(dbc, STK_NOLOCK)) != 0)
00326 goto err;
00327 stack = 1;
00328 goto next;
00329 }
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339 if (LF_ISSET(S_DEL) && cp->csp == cp->sp)
00340 cp->csp++;
00341 BT_STK_ENTER(dbp->dbenv,
00342 cp, h, base, lock, lock_mode, ret);
00343 if (ret != 0)
00344 goto err;
00345 return (0);
00346 }
00347
00348
00349
00350
00351
00352
00353
00354 indx = base > 0 ? base - O_INDX : base;
00355
00356
00357
00358
00359
00360 next: if (recnop != NULL)
00361 for (i = 0; i < indx; ++i)
00362 recno += GET_BINTERNAL(dbp, h, i)->nrecs;
00363
00364 pg = GET_BINTERNAL(dbp, h, indx)->pgno;
00365
00366
00367 if (LF_ISSET(S_START) && slevel == LEVEL(h))
00368 stack = 1;
00369
00370 if (LF_ISSET(S_STK_ONLY)) {
00371 if (slevel == LEVEL(h)) {
00372 BT_STK_NUM(dbp->dbenv, cp, h, indx, ret);
00373 if ((t_ret =
00374 __LPUT(dbc, lock)) != 0 && ret == 0)
00375 ret = t_ret;
00376 if ((t_ret =
00377 __memp_fput(mpf, h, 0)) != 0 && ret == 0)
00378 ret = t_ret;
00379 return (ret);
00380 }
00381 BT_STK_NUMPUSH(dbp->dbenv, cp, h, indx, ret);
00382 (void)__memp_fput(mpf, h, 0);
00383 h = NULL;
00384 if ((ret = __db_lget(dbc,
00385 LCK_COUPLE_ALWAYS, pg, lock_mode, 0, &lock)) != 0) {
00386
00387
00388
00389
00390
00391 (void)__LPUT(dbc, lock);
00392 return (ret);
00393 }
00394 } else if (stack) {
00395
00396 if (LF_ISSET(S_PARENT) && slevel == LEVEL(h)) {
00397 BT_STK_ENTER(dbp->dbenv,
00398 cp, h, indx, lock, lock_mode, ret);
00399 if (ret != 0)
00400 goto err;
00401 return (0);
00402 }
00403 if (LF_ISSET(S_DEL) && NUM_ENT(h) > 1) {
00404
00405
00406
00407
00408 cp->csp--;
00409 if ((ret = __bam_stkrel(dbc, STK_NOLOCK)) != 0)
00410 goto err;
00411 stack = 0;
00412 goto do_del;
00413 }
00414 BT_STK_PUSH(dbp->dbenv,
00415 cp, h, indx, lock, lock_mode, ret);
00416 if (ret != 0)
00417 goto err;
00418 h = NULL;
00419
00420 lock_mode = DB_LOCK_WRITE;
00421 if ((ret =
00422 __db_lget(dbc, 0, pg, lock_mode, 0, &lock)) != 0)
00423 goto err;
00424 } else {
00425
00426
00427
00428
00429
00430 if ((LF_ISSET(S_PARENT) &&
00431 (u_int8_t)(slevel + 1) >= (LEVEL(h) - 1)) ||
00432 (LEVEL(h) - 1) == LEAFLEVEL)
00433 stack = 1;
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 if (!LF_ISSET(S_DEL | S_NEXT)) {
00448 if ((ret = __memp_fput(mpf, h, 0)) != 0)
00449 goto err;
00450 goto lock_next;
00451 }
00452
00453 if ((LF_ISSET(S_DEL) && NUM_ENT(h) == 1)) {
00454 stack = 1;
00455 LF_SET(S_WRITE);
00456
00457 cp->csp++;
00458
00459 BT_STK_PUSH(dbp->dbenv, cp, h,
00460 indx, lock, lock_mode, ret);
00461 if (ret != 0)
00462 goto err;
00463 LOCK_INIT(lock);
00464 } else {
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 do_del: if (cp->csp->page != NULL) {
00475 if (LF_ISSET(S_NEXT) &&
00476 indx == NUM_ENT(h) - 1)
00477 cp->csp++;
00478 else if ((ret =
00479 __bam_stkrel(dbc, STK_NOLOCK)) != 0)
00480 goto err;
00481 }
00482
00483 BT_STK_ENTER(dbp->dbenv, cp,
00484 h, indx, lock, lock_mode, ret);
00485 if (ret != 0)
00486 goto err;
00487 LOCK_INIT(lock);
00488 }
00489
00490 lock_next: h = NULL;
00491
00492 if (stack && LF_ISSET(S_WRITE))
00493 lock_mode = DB_LOCK_WRITE;
00494 if ((ret = __db_lget(dbc,
00495 LCK_COUPLE_ALWAYS, pg, lock_mode, 0, &lock)) != 0) {
00496
00497
00498
00499
00500
00501 (void)__LPUT(dbc, lock);
00502 if (LF_ISSET(S_DEL | S_NEXT))
00503 cp->csp++;
00504 goto err;
00505 }
00506 }
00507 if ((ret = __memp_fget(mpf, &pg, 0, &h)) != 0)
00508 goto err;
00509 }
00510
00511
00512 found: *exactp = 1;
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524 if (TYPE(h) == P_LBTREE && NUM_ENT(h) > P_INDX) {
00525 if (LF_ISSET(S_DUPLAST))
00526 while (indx < (db_indx_t)(NUM_ENT(h) - P_INDX) &&
00527 inp[indx] == inp[indx + P_INDX])
00528 indx += P_INDX;
00529 else if (LF_ISSET(S_DUPFIRST))
00530 while (indx > 0 &&
00531 inp[indx] == inp[indx - P_INDX])
00532 indx -= P_INDX;
00533 }
00534
00535
00536
00537
00538
00539
00540
00541 DB_ASSERT(recnop == NULL || LF_ISSET(S_DELNO));
00542 if (LF_ISSET(S_DELNO)) {
00543 deloffset = TYPE(h) == P_LBTREE ? O_INDX : 0;
00544 if (LF_ISSET(S_DUPLAST))
00545 while (B_DISSET(GET_BKEYDATA(dbp,
00546 h, indx + deloffset)->type) && indx > 0 &&
00547 inp[indx] == inp[indx - adjust])
00548 indx -= adjust;
00549 else
00550 while (B_DISSET(GET_BKEYDATA(dbp,
00551 h, indx + deloffset)->type) &&
00552 indx < (db_indx_t)(NUM_ENT(h) - adjust) &&
00553 inp[indx] == inp[indx + adjust])
00554 indx += adjust;
00555
00556
00557
00558
00559
00560 if (B_DISSET(GET_BKEYDATA(dbp, h, indx + deloffset)->type)) {
00561 ret = DB_NOTFOUND;
00562 goto err;
00563 }
00564
00565
00566
00567
00568
00569
00570
00571 if (recnop != NULL) {
00572 DB_ASSERT(TYPE(h) == P_LBTREE);
00573
00574 for (i = 0; i < indx; i += P_INDX)
00575 if (!B_DISSET(
00576 GET_BKEYDATA(dbp, h, i + O_INDX)->type))
00577 ++recno;
00578
00579
00580 *recnop = recno + 1;
00581 }
00582 }
00583
00584 if (LF_ISSET(S_STK_ONLY)) {
00585 BT_STK_NUM(dbp->dbenv, cp, h, indx, ret);
00586 if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
00587 ret = t_ret;
00588 if ((t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
00589 ret = t_ret;
00590 } else {
00591 if (LF_ISSET(S_DEL) && cp->csp == cp->sp)
00592 cp->csp++;
00593 BT_STK_ENTER(dbp->dbenv, cp, h, indx, lock, lock_mode, ret);
00594 }
00595 if (ret != 0)
00596 goto err;
00597
00598 return (0);
00599
00600 err: if (h != NULL && (t_ret = __memp_fput(mpf, h, 0)) != 0 && ret == 0)
00601 ret = t_ret;
00602
00603
00604 if ((t_ret = __TLPUT(dbc, lock)) != 0 && ret == 0)
00605 ret = t_ret;
00606
00607 BT_STK_POP(cp);
00608 __bam_stkrel(dbc, 0);
00609
00610 return (ret);
00611 }
00612
00613
00614
00615
00616
00617
00618
00619 int
00620 __bam_stkrel(dbc, flags)
00621 DBC *dbc;
00622 u_int32_t flags;
00623 {
00624 BTREE_CURSOR *cp;
00625 DB *dbp;
00626 DB_MPOOLFILE *mpf;
00627 EPG *epg;
00628 int ret, t_ret;
00629
00630 dbp = dbc->dbp;
00631 mpf = dbp->mpf;
00632 cp = (BTREE_CURSOR *)dbc->internal;
00633
00634
00635
00636
00637
00638
00639
00640 for (ret = 0, epg = cp->sp; epg <= cp->csp; ++epg) {
00641 if (epg->page != NULL) {
00642 if (LF_ISSET(STK_CLRDBC) && cp->page == epg->page) {
00643 cp->page = NULL;
00644 LOCK_INIT(cp->lock);
00645 }
00646 if ((t_ret =
00647 __memp_fput(mpf, epg->page, 0)) != 0 && ret == 0)
00648 ret = t_ret;
00649
00650
00651
00652
00653
00654
00655
00656 epg->page = NULL;
00657 }
00658
00659
00660
00661
00662
00663 if (LF_ISSET(STK_PGONLY))
00664 continue;
00665 if (LF_ISSET(STK_NOLOCK)) {
00666 if ((t_ret = __LPUT(dbc, epg->lock)) != 0 && ret == 0)
00667 ret = t_ret;
00668 } else
00669 if ((t_ret = __TLPUT(dbc, epg->lock)) != 0 && ret == 0)
00670 ret = t_ret;
00671 }
00672
00673
00674 if (!LF_ISSET(STK_PGONLY))
00675 BT_STK_CLR(cp);
00676
00677 return (ret);
00678 }
00679
00680
00681
00682
00683
00684
00685
00686 int
00687 __bam_stkgrow(dbenv, cp)
00688 DB_ENV *dbenv;
00689 BTREE_CURSOR *cp;
00690 {
00691 EPG *p;
00692 size_t entries;
00693 int ret;
00694
00695 entries = cp->esp - cp->sp;
00696
00697 if ((ret = __os_calloc(dbenv, entries * 2, sizeof(EPG), &p)) != 0)
00698 return (ret);
00699 memcpy(p, cp->sp, entries * sizeof(EPG));
00700 if (cp->sp != cp->stack)
00701 __os_free(dbenv, cp->sp);
00702 cp->sp = p;
00703 cp->csp = p + entries;
00704 cp->esp = p + entries * 2;
00705 return (0);
00706 }