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 #include "config.h"
00044
00045 #ifndef lint
00046 static const char revid[] = "$Id: bt__put_8c-source.html,v 1.1 2008/06/08 10:13:38 sebdiaz Exp $";
00047 #endif
00048
00049 #ifndef NO_SYSTEM_INCLUDES
00050 #include <sys/types.h>
00051
00052 #include <errno.h>
00053 #include <string.h>
00054 #endif
00055
00056 #include "db_int.h"
00057 #include "db_page.h"
00058 #include "btree.h"
00059
00060 static int __bam_dup_convert __P((DBC *, PAGE *, u_int32_t));
00061 static int __bam_ovput
00062 __P((DBC *, u_int32_t, db_pgno_t, PAGE *, u_int32_t, DBT *));
00063
00064
00065
00066
00067
00068
00069
00070 int
00071 CDB___bam_iitem(dbc, key, data, op, flags)
00072 DBC *dbc;
00073 DBT *key, *data;
00074 u_int32_t op, flags;
00075 {
00076 BKEYDATA *bk, bk_tmp;
00077 BTREE *t;
00078 BTREE_CURSOR *cp;
00079 DB *dbp;
00080 DBT bk_hdr, tdbt;
00081 PAGE *h;
00082 db_indx_t indx;
00083 u_int32_t data_size, have_bytes, need_bytes, needed;
00084 int cmp, bigkey, bigdata, dupadjust, padrec, replace, ret, was_deleted;
00085
00086 COMPQUIET(bk, NULL);
00087
00088 dbp = dbc->dbp;
00089 cp = (BTREE_CURSOR *)dbc->internal;
00090 t = dbp->bt_internal;
00091 h = cp->page;
00092 indx = cp->indx;
00093 dupadjust = replace = was_deleted = 0;
00094
00095
00096
00097
00098
00099 if (F_ISSET(dbp, DB_RE_FIXEDLEN) &&
00100 F_ISSET(data, DB_DBT_PARTIAL) && data->dlen != data->size) {
00101 data_size = data->size;
00102 goto len_err;
00103 }
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113 data_size = F_ISSET(data, DB_DBT_PARTIAL) ?
00114 CDB___bam_partsize(op, data, h, indx) : data->size;
00115 padrec = 0;
00116 if (F_ISSET(dbp, DB_RE_FIXEDLEN)) {
00117 if (data_size > t->re_len) {
00118 len_err: CDB___db_err(dbp->dbenv,
00119 "Length improper for fixed length record %lu",
00120 (u_long)data_size);
00121 return (EINVAL);
00122 }
00123 if (data_size < t->re_len) {
00124 padrec = 1;
00125 data_size = t->re_len;
00126 }
00127 }
00128
00129
00130
00131
00132
00133 if (padrec || F_ISSET(data, DB_DBT_PARTIAL)) {
00134 tdbt = *data;
00135 if ((ret =
00136 CDB___bam_build(dbc, op, &tdbt, h, indx, data_size)) != 0)
00137 return (ret);
00138 data = &tdbt;
00139 }
00140
00141
00142
00143
00144
00145
00146
00147
00148 if (op == DB_CURRENT && dbp->dup_compare != NULL) {
00149 if ((ret = CDB___bam_cmp(dbp, data, h,
00150 indx + (TYPE(h) == P_LBTREE ? O_INDX : 0),
00151 dbp->dup_compare, &cmp)) != 0)
00152 return (ret);
00153 if (cmp != 0) {
00154 CDB___db_err(dbp->dbenv,
00155 "Current data differs from put data");
00156 return (EINVAL);
00157 }
00158 }
00159
00160
00161
00162
00163
00164 needed = 0;
00165 bigdata = data_size > cp->ovflsize;
00166 switch (op) {
00167 case DB_KEYFIRST:
00168
00169 bigkey = key->size > cp->ovflsize;
00170 if (bigkey)
00171 needed += BOVERFLOW_PSIZE;
00172 else
00173 needed += BKEYDATA_PSIZE(key->size);
00174 if (bigdata)
00175 needed += BOVERFLOW_PSIZE;
00176 else
00177 needed += BKEYDATA_PSIZE(data_size);
00178 break;
00179 case DB_AFTER:
00180 case DB_BEFORE:
00181 case DB_CURRENT:
00182
00183
00184
00185
00186
00187
00188
00189
00190
00191
00192 bigkey = 0;
00193 if (op == DB_CURRENT) {
00194 bk = GET_BKEYDATA(h,
00195 indx + (TYPE(h) == P_LBTREE ? O_INDX : 0));
00196 if (B_TYPE(bk->type) == B_KEYDATA)
00197 have_bytes = BKEYDATA_PSIZE(bk->len);
00198 else
00199 have_bytes = BOVERFLOW_PSIZE;
00200 need_bytes = 0;
00201 } else {
00202 have_bytes = 0;
00203 need_bytes = sizeof(db_indx_t);
00204 }
00205 if (bigdata)
00206 need_bytes += BOVERFLOW_PSIZE;
00207 else
00208 need_bytes += BKEYDATA_PSIZE(data_size);
00209
00210 if (have_bytes < need_bytes)
00211 needed += need_bytes - have_bytes;
00212 break;
00213 default:
00214 return (CDB___db_unknown_flag(dbp->dbenv, "CDB___bam_iitem", op));
00215 }
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 if (P_FREESPACE(h) < needed ||
00226 (t->bt_maxkey != 0 && NUM_ENT(h) > t->bt_maxkey))
00227 return (DB_NEEDSPLIT);
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238 switch (op) {
00239 case DB_KEYFIRST:
00240 if (bigkey) {
00241 if ((ret = __bam_ovput(dbc,
00242 B_OVERFLOW, PGNO_INVALID, h, indx, key)) != 0)
00243 return (ret);
00244 } else
00245 if ((ret = CDB___db_pitem(dbc, h, indx,
00246 BKEYDATA_SIZE(key->size), NULL, key)) != 0)
00247 return (ret);
00248
00249 CDB___bam_ca_di(dbp, PGNO(h), indx, 1);
00250 ++indx;
00251 break;
00252 case DB_AFTER:
00253 if (TYPE(h) == P_LBTREE) {
00254
00255 if ((ret =
00256 CDB___bam_adjindx(dbc, h, indx + P_INDX, indx, 1)) != 0)
00257 return (ret);
00258 CDB___bam_ca_di(dbp, PGNO(h), indx + P_INDX, 1);
00259
00260 indx += 3;
00261 dupadjust = 1;
00262
00263 cp->indx += 2;
00264 } else {
00265 ++indx;
00266 CDB___bam_ca_di(dbp, PGNO(h), indx, 1);
00267
00268 cp->indx += 1;
00269 }
00270 break;
00271 case DB_BEFORE:
00272 if (TYPE(h) == P_LBTREE) {
00273
00274 if ((ret = CDB___bam_adjindx(dbc, h, indx, indx, 1)) != 0)
00275 return (ret);
00276 CDB___bam_ca_di(dbp, PGNO(h), indx, 1);
00277
00278 ++indx;
00279 dupadjust = 1;
00280 } else
00281 CDB___bam_ca_di(dbp, PGNO(h), indx, 1);
00282 break;
00283 case DB_CURRENT:
00284 if (TYPE(h) == P_LBTREE) {
00285 ++indx;
00286 dupadjust = 1;
00287
00288
00289
00290
00291
00292
00293
00294
00295 was_deleted = B_DISSET(bk->type);
00296 }
00297
00298
00299
00300
00301
00302
00303
00304
00305
00306
00307 if (bigdata || B_TYPE(bk->type) != B_KEYDATA) {
00308 if ((ret = CDB___bam_ditem(dbc, h, indx)) != 0)
00309 return (ret);
00310 break;
00311 }
00312
00313
00314 replace = 1;
00315 break;
00316 default:
00317 return (CDB___db_unknown_flag(dbp->dbenv, "CDB___bam_iitem", op));
00318 }
00319
00320
00321 if (bigdata) {
00322 if ((ret = __bam_ovput(dbc,
00323 B_OVERFLOW, PGNO_INVALID, h, indx, data)) != 0)
00324 return (ret);
00325 } else {
00326 if (LF_ISSET(BI_DELETED)) {
00327 B_TSET(bk_tmp.type, B_KEYDATA, 1);
00328 bk_tmp.len = data->size;
00329 bk_hdr.data = &bk_tmp;
00330 bk_hdr.size = SSZA(BKEYDATA, data);
00331 ret = CDB___db_pitem(dbc, h, indx,
00332 BKEYDATA_SIZE(data->size), &bk_hdr, data);
00333 } else if (replace)
00334 ret = CDB___bam_ritem(dbc, h, indx, data);
00335 else
00336 ret = CDB___db_pitem(dbc, h, indx,
00337 BKEYDATA_SIZE(data->size), NULL, data);
00338 if (ret != 0)
00339 return (ret);
00340 }
00341 if ((ret = CDB_memp_fset(dbp->mpf, h, DB_MPOOL_DIRTY)) != 0)
00342 return (ret);
00343
00344
00345
00346
00347
00348 if (op == DB_CURRENT)
00349 (void)CDB___bam_ca_delete(dbp, PGNO(h),
00350 TYPE(h) == P_LBTREE ? indx - O_INDX : indx, 0);
00351 else {
00352 CDB___bam_ca_di(dbp, PGNO(h), indx, 1);
00353 cp->indx = TYPE(h) == P_LBTREE ? indx - O_INDX : indx;
00354 }
00355
00356
00357
00358
00359
00360
00361 if (F_ISSET(cp, C_RECNUM) && (op != DB_CURRENT || was_deleted))
00362 if ((ret = CDB___bam_adjust(dbc, 1)) != 0)
00363 return (ret);
00364
00365
00366
00367
00368
00369
00370
00371 if (dupadjust && P_FREESPACE(h) <= dbp->pgsize / 2) {
00372 if ((ret = __bam_dup_convert(dbc, h, indx - O_INDX)) != 0)
00373 return (ret);
00374 }
00375
00376
00377 if (dbc->dbtype == DB_RECNO)
00378 F_SET(t, RECNO_MODIFIED);
00379
00380 return (ret);
00381 }
00382
00383
00384
00385
00386
00387
00388
00389 u_int32_t
00390 CDB___bam_partsize(op, data, h, indx)
00391 u_int32_t op, indx;
00392 DBT *data;
00393 PAGE *h;
00394 {
00395 BKEYDATA *bk;
00396 u_int32_t nbytes;
00397
00398
00399
00400
00401
00402 if (op != DB_CURRENT)
00403 return (data->doff + data->size);
00404
00405
00406
00407
00408
00409 bk = GET_BKEYDATA(h, indx + (TYPE(h) == P_LBTREE ? O_INDX : 0));
00410 nbytes =
00411 B_TYPE(bk->type) == B_OVERFLOW ? ((BOVERFLOW *)bk)->tlen : bk->len;
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427 if (nbytes < data->doff + data->dlen)
00428 return (data->doff + data->size);
00429
00430 return (nbytes + data->size - data->dlen);
00431 }
00432
00433
00434
00435
00436
00437
00438
00439
00440 int
00441 CDB___bam_build(dbc, op, dbt, h, indx, nbytes)
00442 DBC *dbc;
00443 u_int32_t op, indx, nbytes;
00444 DBT *dbt;
00445 PAGE *h;
00446 {
00447 BKEYDATA *bk, tbk;
00448 BOVERFLOW *bo;
00449 BTREE *t;
00450 BTREE_CURSOR *cp;
00451 DB *dbp;
00452 DBT copy;
00453 u_int32_t len, tlen;
00454 u_int8_t *p;
00455 int ret;
00456
00457 COMPQUIET(bo, NULL);
00458
00459 dbp = dbc->dbp;
00460 cp = (BTREE_CURSOR *) dbc->internal;
00461 t = dbp->bt_internal;
00462
00463
00464 if (dbc->rdata.ulen < nbytes) {
00465 if ((ret = CDB___os_realloc(dbp->dbenv,
00466 nbytes, NULL, &dbc->rdata.data)) != 0) {
00467 dbc->rdata.ulen = 0;
00468 dbc->rdata.data = NULL;
00469 return (ret);
00470 }
00471 dbc->rdata.ulen = nbytes;
00472 }
00473
00474
00475
00476
00477
00478 memset(dbc->rdata.data,
00479 F_ISSET(dbp, DB_RE_FIXEDLEN) ? t->re_pad : 0, nbytes);
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490 if (!F_ISSET(dbt, DB_DBT_PARTIAL) || op != DB_CURRENT) {
00491 p = (u_int8_t *)dbc->rdata.data + dbt->doff;
00492 tlen = dbt->doff;
00493 goto user_copy;
00494 }
00495
00496
00497 if (indx < NUM_ENT(h)) {
00498 bk = GET_BKEYDATA(h, indx + (TYPE(h) == P_LBTREE ? O_INDX : 0));
00499 bo = (BOVERFLOW *)bk;
00500 } else {
00501 bk = &tbk;
00502 B_TSET(bk->type, B_KEYDATA, 0);
00503 bk->len = 0;
00504 }
00505 if (B_TYPE(bk->type) == B_OVERFLOW) {
00506
00507
00508
00509
00510 memset(©, 0, sizeof(copy));
00511 if ((ret = CDB___db_goff(dbp, ©, bo->tlen,
00512 bo->pgno, &dbc->rdata.data, &dbc->rdata.ulen)) != 0)
00513 return (ret);
00514
00515
00516 tlen = dbt->doff;
00517 p = (u_int8_t *)dbc->rdata.data + dbt->doff;
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530 if (bo->tlen > dbt->doff + dbt->dlen) {
00531 len = bo->tlen - (dbt->doff + dbt->dlen);
00532 if (dbt->dlen != dbt->size)
00533 memmove(p + dbt->size, p + dbt->dlen, len);
00534 tlen += len;
00535 }
00536 } else {
00537
00538 memcpy(dbc->rdata.data,
00539 bk->data, dbt->doff > bk->len ? bk->len : dbt->doff);
00540 tlen = dbt->doff;
00541 p = (u_int8_t *)dbc->rdata.data + dbt->doff;
00542
00543
00544 len = dbt->doff + dbt->dlen;
00545 if (bk->len > len) {
00546 memcpy(p + dbt->size, bk->data + len, bk->len - len);
00547 tlen += bk->len - len;
00548 }
00549 }
00550
00551 user_copy:
00552
00553
00554
00555
00556 memcpy(p, dbt->data, dbt->size);
00557 tlen += dbt->size;
00558
00559
00560 dbc->rdata.size = F_ISSET(dbp, DB_RE_FIXEDLEN) ? t->re_len : tlen;
00561 dbc->rdata.dlen = 0;
00562 dbc->rdata.doff = 0;
00563 dbc->rdata.flags = 0;
00564 *dbt = dbc->rdata;
00565 return (0);
00566 }
00567
00568
00569
00570
00571
00572
00573
00574 int
00575 CDB___bam_ritem(dbc, h, indx, data)
00576 DBC *dbc;
00577 PAGE *h;
00578 u_int32_t indx;
00579 DBT *data;
00580 {
00581 BKEYDATA *bk;
00582 DB *dbp;
00583 DBT orig, repl;
00584 db_indx_t cnt, lo, ln, min, off, prefix, suffix;
00585 int32_t nbytes;
00586 int ret;
00587 u_int8_t *p, *t;
00588
00589 dbp = dbc->dbp;
00590
00591
00592
00593
00594
00595
00596 bk = GET_BKEYDATA(h, indx);
00597
00598
00599 if (DB_LOGGING(dbc)) {
00600
00601
00602
00603
00604
00605 min = data->size < bk->len ? data->size : bk->len;
00606 for (prefix = 0,
00607 p = bk->data, t = data->data;
00608 prefix < min && *p == *t; ++prefix, ++p, ++t)
00609 ;
00610
00611 min -= prefix;
00612 for (suffix = 0,
00613 p = (u_int8_t *)bk->data + bk->len - 1,
00614 t = (u_int8_t *)data->data + data->size - 1;
00615 suffix < min && *p == *t; ++suffix, --p, --t)
00616 ;
00617
00618
00619 orig.data = (u_int8_t *)bk->data + prefix;
00620 orig.size = bk->len - (prefix + suffix);
00621 repl.data = (u_int8_t *)data->data + prefix;
00622 repl.size = data->size - (prefix + suffix);
00623 if ((ret = CDB___bam_repl_log(dbp->dbenv, dbc->txn,
00624 &LSN(h), 0, dbp->log_fileid, PGNO(h), &LSN(h),
00625 (u_int32_t)indx, (u_int32_t)B_DISSET(bk->type),
00626 &orig, &repl, (u_int32_t)prefix, (u_int32_t)suffix)) != 0)
00627 return (ret);
00628 }
00629
00630
00631
00632
00633
00634 p = (u_int8_t *)h + HOFFSET(h);
00635 t = (u_int8_t *)bk;
00636
00637
00638
00639
00640
00641
00642
00643 lo = BKEYDATA_SIZE(bk->len);
00644 ln = BKEYDATA_SIZE(data->size);
00645 if (lo != ln) {
00646 nbytes = lo - ln;
00647 if (p == t)
00648 h->inp[indx] += nbytes;
00649 else {
00650 memmove(p + nbytes, p, t - p);
00651
00652
00653 off = h->inp[indx];
00654 for (cnt = 0; cnt < NUM_ENT(h); ++cnt)
00655 if (h->inp[cnt] <= off)
00656 h->inp[cnt] += nbytes;
00657 }
00658
00659
00660 HOFFSET(h) += nbytes;
00661 t += nbytes;
00662 }
00663
00664
00665 bk = (BKEYDATA *)t;
00666 B_TSET(bk->type, B_KEYDATA, 0);
00667 bk->len = data->size;
00668 memcpy(bk->data, data->data, data->size);
00669
00670 return (0);
00671 }
00672
00673
00674
00675
00676
00677
00678 static int
00679 __bam_dup_convert(dbc, h, indx)
00680 DBC *dbc;
00681 PAGE *h;
00682 u_int32_t indx;
00683 {
00684 BTREE_CURSOR *cp;
00685 BKEYDATA *bk;
00686 DB *dbp;
00687 DBT hdr;
00688 PAGE *dp;
00689 db_indx_t cnt, cpindx, first, sz;
00690 int ret;
00691
00692 dbp = dbc->dbp;
00693 cp = (BTREE_CURSOR *) dbc->internal;
00694
00695
00696
00697
00698
00699 while (indx > 0 && h->inp[indx] == h->inp[indx - P_INDX])
00700 indx -= P_INDX;
00701 for (cnt = 0, sz = 0, first = indx;; ++cnt, indx += P_INDX) {
00702 if (indx >= NUM_ENT(h) || h->inp[first] != h->inp[indx])
00703 break;
00704 bk = GET_BKEYDATA(h, indx);
00705 sz += B_TYPE(bk->type) == B_KEYDATA ?
00706 BKEYDATA_PSIZE(bk->len) : BOVERFLOW_PSIZE;
00707 bk = GET_BKEYDATA(h, indx + O_INDX);
00708 sz += B_TYPE(bk->type) == B_KEYDATA ?
00709 BKEYDATA_PSIZE(bk->len) : BOVERFLOW_PSIZE;
00710 }
00711
00712
00713
00714
00715
00716
00717
00718
00719 if (cnt == 1)
00720 return (0);
00721
00722
00723
00724
00725
00726
00727
00728 if (sz < dbp->pgsize / 4)
00729 return (0);
00730
00731
00732 if ((ret = CDB___db_new(dbc,
00733 ((dbp->dup_compare == NULL ? P_LRECNO : P_LDUP) | dbp->tags), &dp)) != 0)
00734 return (ret);
00735 P_INIT(dp, dbp->pgsize, dp->pgno,
00736 PGNO_INVALID, PGNO_INVALID, LEAFLEVEL, TYPE(dp), TAGS(dp));
00737
00738
00739
00740
00741
00742
00743 memset(&hdr, 0, sizeof(hdr));
00744 for (indx = first + O_INDX, cpindx = 0;;) {
00745
00746 if ((ret = CDB___bam_ca_dup(dbp, first,
00747 PGNO(h), indx - O_INDX, PGNO(dp), cpindx)) != 0)
00748 goto err;
00749
00750
00751
00752
00753
00754
00755 bk = GET_BKEYDATA(h, indx);
00756 hdr.data = bk;
00757 hdr.size = B_TYPE(bk->type) == B_KEYDATA ?
00758 BKEYDATA_SIZE(bk->len) : BOVERFLOW_SIZE;
00759 if (dbp->dup_compare != NULL || !B_DISSET(bk->type)) {
00760 if ((ret = CDB___db_pitem(
00761 dbc, dp, cpindx, hdr.size, &hdr, NULL)) != 0)
00762 goto err;
00763 ++cpindx;
00764 }
00765
00766
00767 if ((ret = CDB___db_ditem(dbc, h, indx, hdr.size)) != 0)
00768 goto err;
00769 CDB___bam_ca_di(dbp, PGNO(h), indx, -1);
00770
00771
00772 if (--cnt == 0)
00773 break;
00774 if ((ret = CDB___bam_adjindx(dbc, h, indx, first, 0)) != 0)
00775 goto err;
00776 CDB___bam_ca_di(dbp, PGNO(h), indx, -1);
00777 }
00778
00779
00780 if ((ret = __bam_ovput(dbc, B_DUPLICATE, dp->pgno, h, indx, NULL)) != 0)
00781 goto err;
00782
00783 return (CDB_memp_fput(dbp->mpf, dp, DB_MPOOL_DIRTY));
00784
00785 err: (void)CDB___db_free(dbc, dp);
00786 return (ret);
00787 }
00788
00789
00790
00791
00792
00793
00794 static int
00795 __bam_ovput(dbc, type, pgno, h, indx, item)
00796 DBC *dbc;
00797 u_int32_t type, indx;
00798 db_pgno_t pgno;
00799 PAGE *h;
00800 DBT *item;
00801 {
00802 BOVERFLOW bo;
00803 DBT hdr;
00804 int ret;
00805
00806 UMRW(bo.unused1);
00807 B_TSET(bo.type, type, 0);
00808 UMRW(bo.unused2);
00809
00810
00811
00812
00813
00814
00815 if (type == B_OVERFLOW) {
00816 if ((ret = CDB___db_poff(dbc, item, &bo.pgno)) != 0)
00817 return (ret);
00818 bo.tlen = item->size;
00819 } else {
00820 bo.pgno = pgno;
00821 bo.tlen = 0;
00822 }
00823
00824
00825 memset(&hdr, 0, sizeof(hdr));
00826 hdr.data = &bo;
00827 hdr.size = BOVERFLOW_SIZE;
00828 return (CDB___db_pitem(dbc, h, indx, BOVERFLOW_SIZE, &hdr, NULL));
00829 }