~ubuntu-branches/ubuntu/edgy/rpm/edgy

« back to all changes in this revision

Viewing changes to db/btree/bt_recno.c

  • Committer: Bazaar Package Importer
  • Author(s): Joey Hess
  • Date: 2002-01-22 20:56:57 UTC
  • Revision ID: james.westby@ubuntu.com-20020122205657-l74j50mr9z8ofcl5
Tags: upstream-4.0.3
ImportĀ upstreamĀ versionĀ 4.0.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-
 
2
 * See the file LICENSE for redistribution information.
 
3
 *
 
4
 * Copyright (c) 1997-2001
 
5
 *      Sleepycat Software.  All rights reserved.
 
6
 */
 
7
 
 
8
#include "db_config.h"
 
9
 
 
10
#ifndef lint
 
11
static const char revid[] = "$Id: bt_recno.c,v 11.81 2001/07/02 01:05:35 bostic Exp $";
 
12
#endif /* not lint */
 
13
 
 
14
#ifndef NO_SYSTEM_INCLUDES
 
15
#include <sys/types.h>
 
16
 
 
17
#include <limits.h>
 
18
#include <stdio.h>
 
19
#include <string.h>
 
20
#endif
 
21
 
 
22
#include "db_int.h"
 
23
#include "db_page.h"
 
24
#include "btree.h"
 
25
#include "db_ext.h"
 
26
#include "db_shash.h"
 
27
#include "lock.h"
 
28
#include "lock_ext.h"
 
29
#include "qam.h"
 
30
#include "txn.h"
 
31
 
 
32
static int  __ram_add __P((DBC *, db_recno_t *, DBT *, u_int32_t, u_int32_t));
 
33
static int  __ram_source __P((DB *));
 
34
static int  __ram_sread __P((DBC *, db_recno_t));
 
35
static int  __ram_update __P((DBC *, db_recno_t, int));
 
36
 
 
37
/*
 
38
 * In recno, there are two meanings to the on-page "deleted" flag.  If we're
 
39
 * re-numbering records, it means the record was implicitly created.  We skip
 
40
 * over implicitly created records if doing a cursor "next" or "prev", and
 
41
 * return DB_KEYEMPTY if they're explicitly requested..  If not re-numbering
 
42
 * records, it means that the record was implicitly created, or was deleted.
 
43
 * We skip over implicitly created or deleted records if doing a cursor "next"
 
44
 * or "prev", and return DB_KEYEMPTY if they're explicitly requested.
 
45
 *
 
46
 * If we're re-numbering records, then we have to detect in the cursor that
 
47
 * a record was deleted, and adjust the cursor as necessary on the next get.
 
48
 * If we're not re-numbering records, then we can detect that a record has
 
49
 * been deleted by looking at the actual on-page record, so we completely
 
50
 * ignore the cursor's delete flag.  This is different from the B+tree code.
 
51
 * It also maintains whether the cursor references a deleted record in the
 
52
 * cursor, and it doesn't always check the on-page value.
 
53
 */
 
54
#define CD_SET(cp) {                                                    \
 
55
        if (F_ISSET(cp, C_RENUMBER))                                    \
 
56
                F_SET(cp, C_DELETED);                                   \
 
57
}
 
58
#define CD_CLR(cp) {                                                    \
 
59
        if (F_ISSET(cp, C_RENUMBER)) {                                  \
 
60
                F_CLR(cp, C_DELETED);                                   \
 
61
                cp->order = INVALID_ORDER;                              \
 
62
        }                                                               \
 
63
}
 
64
#define CD_ISSET(cp)                                                    \
 
65
        (F_ISSET(cp, C_RENUMBER) && F_ISSET(cp, C_DELETED))
 
66
 
 
67
/*
 
68
 * Macros for comparing the ordering of two cursors.
 
69
 * cp1 comes before cp2 iff one of the following holds:
 
70
 *      cp1's recno is less than cp2's recno
 
71
 *      recnos are equal, both deleted, and cp1's order is less than cp2's
 
72
 *      recnos are equal, cp1 deleted, and cp2 not deleted
 
73
 */
 
74
#define C_LESSTHAN(cp1, cp2)                                            \
 
75
    (((cp1)->recno < (cp2)->recno) ||                                   \
 
76
    (((cp1)->recno == (cp2)->recno) &&                                  \
 
77
    ((CD_ISSET((cp1)) && CD_ISSET((cp2)) && (cp1)->order < (cp2)->order) || \
 
78
    (CD_ISSET((cp1)) && !CD_ISSET((cp2))))))
 
79
 
 
80
/*
 
81
 * cp1 is equal to cp2 iff their recnos and delete flags are identical,
 
82
 * and if the delete flag is set their orders are also identical.
 
83
 */
 
84
#define C_EQUAL(cp1, cp2)                                               \
 
85
    ((cp1)->recno == (cp2)->recno && CD_ISSET((cp1)) == CD_ISSET((cp2)) && \
 
86
    (!CD_ISSET((cp1)) || (cp1)->order == (cp2)->order))
 
87
 
 
88
/*
 
89
 * Do we need to log the current cursor adjustment?
 
90
 */
 
91
#define CURADJ_LOG(dbc)                                                 \
 
92
        (DB_LOGGING((dbc)) && (dbc)->txn != NULL && (dbc)->txn->parent != NULL)
 
93
 
 
94
/*
 
95
 * __ram_open --
 
96
 *      Recno open function.
 
97
 *
 
98
 * PUBLIC: int __ram_open __P((DB *, const char *, db_pgno_t, u_int32_t));
 
99
 */
 
100
int
 
101
__ram_open(dbp, name, base_pgno, flags)
 
102
        DB *dbp;
 
103
        const char *name;
 
104
        db_pgno_t base_pgno;
 
105
        u_int32_t flags;
 
106
{
 
107
        BTREE *t;
 
108
        DBC *dbc;
 
109
        int ret, t_ret;
 
110
 
 
111
        t = dbp->bt_internal;
 
112
 
 
113
        /* Initialize the remaining fields/methods of the DB. */
 
114
        dbp->stat = __bam_stat;
 
115
 
 
116
        /* Start up the tree. */
 
117
        if ((ret = __bam_read_root(dbp, name, base_pgno, flags)) != 0)
 
118
                return (ret);
 
119
 
 
120
        /*
 
121
         * If the user specified a source tree, open it and map it in.
 
122
         *
 
123
         * !!!
 
124
         * We don't complain if the user specified transactions or threads.
 
125
         * It's possible to make it work, but you'd better know what you're
 
126
         * doing!
 
127
         */
 
128
        if (t->re_source != NULL && (ret = __ram_source(dbp)) != 0)
 
129
                return (ret);
 
130
 
 
131
        /* If we're snapshotting an underlying source file, do it now. */
 
132
        if (F_ISSET(dbp, DB_RE_SNAPSHOT)) {
 
133
                /* Allocate a cursor. */
 
134
                if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
 
135
                        return (ret);
 
136
 
 
137
                /* Do the snapshot. */
 
138
                if ((ret = __ram_update(dbc,
 
139
                    DB_MAX_RECORDS, 0)) != 0 && ret == DB_NOTFOUND)
 
140
                        ret = 0;
 
141
 
 
142
                /* Discard the cursor. */
 
143
                if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
 
144
                        ret = t_ret;
 
145
        }
 
146
 
 
147
        return (0);
 
148
}
 
149
 
 
150
/*
 
151
 * __ram_append --
 
152
 *      Recno append function.
 
153
 *
 
154
 * PUBLIC: int __ram_append __P((DBC *, DBT *, DBT *));
 
155
 */
 
156
int
 
157
__ram_append(dbc, key, data)
 
158
        DBC *dbc;
 
159
        DBT *key, *data;
 
160
{
 
161
        BTREE_CURSOR *cp;
 
162
        int ret;
 
163
 
 
164
        cp = (BTREE_CURSOR *)dbc->internal;
 
165
 
 
166
        /*
 
167
         * Make sure we've read in all of the backing source file.  If
 
168
         * we found the record or it simply didn't exist, add the
 
169
         * user's record.
 
170
         */
 
171
        ret = __ram_update(dbc, DB_MAX_RECORDS, 0);
 
172
        if (ret == 0 || ret == DB_NOTFOUND)
 
173
                ret = __ram_add(dbc, &cp->recno, data, DB_APPEND, 0);
 
174
 
 
175
        /* Return the record number. */
 
176
        if (ret == 0)
 
177
                ret = __db_retcopy(dbc->dbp, key, &cp->recno, sizeof(cp->recno),
 
178
                    &dbc->rkey->data, &dbc->rkey->ulen);
 
179
 
 
180
        return (ret);
 
181
}
 
182
 
 
183
/*
 
184
 * __ram_c_del --
 
185
 *      Recno cursor->c_del function.
 
186
 *
 
187
 * PUBLIC: int __ram_c_del __P((DBC *));
 
188
 */
 
189
int
 
190
__ram_c_del(dbc)
 
191
        DBC *dbc;
 
192
{
 
193
        BKEYDATA bk;
 
194
        BTREE *t;
 
195
        BTREE_CURSOR *cp;
 
196
        DB *dbp;
 
197
        DB_LSN lsn;
 
198
        DBT hdr, data;
 
199
        EPG *epg;
 
200
        int exact, ret, stack;
 
201
 
 
202
        dbp = dbc->dbp;
 
203
        cp = (BTREE_CURSOR *)dbc->internal;
 
204
        t = dbp->bt_internal;
 
205
        stack = 0;
 
206
 
 
207
        /*
 
208
         * The semantics of cursors during delete are as follows: in
 
209
         * non-renumbering recnos, records are replaced with a marker
 
210
         * containing a delete flag.  If the record referenced by this cursor
 
211
         * has already been deleted, we will detect that as part of the delete
 
212
         * operation, and fail.
 
213
         *
 
214
         * In renumbering recnos, cursors which represent deleted items
 
215
         * are flagged with the C_DELETED flag, and it is an error to
 
216
         * call c_del a second time without an intervening cursor motion.
 
217
         */
 
218
        if (CD_ISSET(cp))
 
219
                return (DB_KEYEMPTY);
 
220
 
 
221
        /* Search the tree for the key; delete only deletes exact matches. */
 
222
        if ((ret = __bam_rsearch(dbc, &cp->recno, S_DELETE, 1, &exact)) != 0)
 
223
                goto err;
 
224
        if (!exact) {
 
225
                ret = DB_NOTFOUND;
 
226
                goto err;
 
227
        }
 
228
        stack = 1;
 
229
        cp->page = cp->csp->page;
 
230
        cp->pgno = cp->csp->page->pgno;
 
231
        cp->indx = cp->csp->indx;
 
232
 
 
233
        /*
 
234
         * If re-numbering records, the on-page deleted flag can only mean
 
235
         * that this record was implicitly created.  Applications aren't
 
236
         * permitted to delete records they never created, return an error.
 
237
         *
 
238
         * If not re-numbering records, the on-page deleted flag means that
 
239
         * this record was implicitly created, or, was deleted at some time.
 
240
         * The former is an error because applications aren't permitted to
 
241
         * delete records they never created, the latter is an error because
 
242
         * if the record was "deleted", we could never have found it.
 
243
         */
 
244
        if (B_DISSET(GET_BKEYDATA(cp->page, cp->indx)->type)) {
 
245
                ret = DB_KEYEMPTY;
 
246
                goto err;
 
247
        }
 
248
 
 
249
        if (F_ISSET(cp, C_RENUMBER)) {
 
250
                /* Delete the item, adjust the counts, adjust the cursors. */
 
251
                if ((ret = __bam_ditem(dbc, cp->page, cp->indx)) != 0)
 
252
                        goto err;
 
253
                __bam_adjust(dbc, -1);
 
254
                if (__ram_ca(dbc, CA_DELETE) > 0 &&
 
255
                    CURADJ_LOG(dbc) && (ret = __bam_rcuradj_log(dbp->dbenv,
 
256
                    dbc->txn, &lsn, 0, dbp->log_fileid, CA_DELETE,
 
257
                    cp->root, cp->recno, cp->order)) != 0)
 
258
                        goto err;
 
259
 
 
260
                /*
 
261
                 * If the page is empty, delete it.
 
262
                 *
 
263
                 * We never delete a root page.  First, root pages of primary
 
264
                 * databases never go away, recno or otherwise.  However, if
 
265
                 * it's the root page of an off-page duplicates database, then
 
266
                 * it can be deleted.   We don't delete it here because we have
 
267
                 * no way of telling the primary database page holder (e.g.,
 
268
                 * the hash access method) that its page element should cleaned
 
269
                 * up because the underlying tree is gone.  So, we keep the page
 
270
                 * around until the last cursor referencing the empty tree is
 
271
                 * are closed, and then clean it up.
 
272
                 */
 
273
                if (NUM_ENT(cp->page) == 0 && PGNO(cp->page) != cp->root) {
 
274
                        /*
 
275
                         * We already have a locked stack of pages.  However,
 
276
                         * there are likely entries in the stack that aren't
 
277
                         * going to be emptied by removing the single reference
 
278
                         * to the emptied page (or one of its parents).
 
279
                         */
 
280
                        for (epg = cp->sp; epg <= cp->csp; ++epg)
 
281
                                if (NUM_ENT(epg->page) <= 1)
 
282
                                        break;
 
283
 
 
284
                        /*
 
285
                         * We want to delete a single item out of the last page
 
286
                         * that we're not deleting, back up to that page.
 
287
                         */
 
288
                        ret = __bam_dpages(dbc, --epg);
 
289
 
 
290
                        /*
 
291
                         * Regardless of the return from __bam_dpages, it will
 
292
                         * discard our stack and pinned page.
 
293
                         */
 
294
                        stack = 0;
 
295
                        cp->page = NULL;
 
296
                }
 
297
        } else {
 
298
                /* Use a delete/put pair to replace the record with a marker. */
 
299
                if ((ret = __bam_ditem(dbc, cp->page, cp->indx)) != 0)
 
300
                        goto err;
 
301
 
 
302
                B_TSET(bk.type, B_KEYDATA, 1);
 
303
                bk.len = 0;
 
304
                memset(&hdr, 0, sizeof(hdr));
 
305
                hdr.data = &bk;
 
306
                hdr.size = SSZA(BKEYDATA, data);
 
307
                memset(&data, 0, sizeof(data));
 
308
                data.data = (void *)"";
 
309
                data.size = 0;
 
310
                if ((ret = __db_pitem(dbc,
 
311
                    cp->page, cp->indx, BKEYDATA_SIZE(0), &hdr, &data)) != 0)
 
312
                        goto err;
 
313
        }
 
314
 
 
315
        t->re_modified = 1;
 
316
 
 
317
err:    if (stack)
 
318
                __bam_stkrel(dbc, STK_CLRDBC);
 
319
 
 
320
        return (ret);
 
321
}
 
322
 
 
323
/*
 
324
 * __ram_c_get --
 
325
 *      Recno cursor->c_get function.
 
326
 *
 
327
 * PUBLIC: int __ram_c_get
 
328
 * PUBLIC:     __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *));
 
329
 */
 
330
int
 
331
__ram_c_get(dbc, key, data, flags, pgnop)
 
332
        DBC *dbc;
 
333
        DBT *key, *data;
 
334
        u_int32_t flags;
 
335
        db_pgno_t *pgnop;
 
336
{
 
337
        BTREE_CURSOR *cp;
 
338
        DB *dbp;
 
339
        int cmp, exact, ret;
 
340
 
 
341
        COMPQUIET(pgnop, NULL);
 
342
 
 
343
        dbp = dbc->dbp;
 
344
        cp = (BTREE_CURSOR *)dbc->internal;
 
345
 
 
346
        LF_CLR(DB_MULTIPLE|DB_MULTIPLE_KEY);
 
347
retry:  switch (flags) {
 
348
        case DB_CURRENT:
 
349
                /*
 
350
                 * If we're using mutable records and the deleted flag is
 
351
                 * set, the cursor is pointing at a nonexistent record;
 
352
                 * return an error.
 
353
                 */
 
354
                if (CD_ISSET(cp))
 
355
                        return (DB_KEYEMPTY);
 
356
                break;
 
357
        case DB_NEXT_DUP:
 
358
                /*
 
359
                 * If we're not in an off-page dup set, we know there's no
 
360
                 * next duplicate since recnos don't have them.  If we
 
361
                 * are in an off-page dup set, the next item assuredly is
 
362
                 * a dup, so we set flags to DB_NEXT and keep going.
 
363
                 */
 
364
                if (!F_ISSET(dbc, DBC_OPD))
 
365
                        return (DB_NOTFOUND);
 
366
                /* FALLTHROUGH */
 
367
        case DB_NEXT_NODUP:
 
368
                /*
 
369
                 * Recno databases don't have duplicates, set flags to DB_NEXT
 
370
                 * and keep going.
 
371
                 */
 
372
                /* FALLTHROUGH */
 
373
        case DB_NEXT:
 
374
                flags = DB_NEXT;
 
375
                /*
 
376
                 * If record numbers are mutable: if we just deleted a record,
 
377
                 * we have to avoid incrementing the record number so that we
 
378
                 * return the right record by virtue of renumbering the tree.
 
379
                 */
 
380
                if (CD_ISSET(cp))
 
381
                        break;
 
382
 
 
383
                if (cp->recno != RECNO_OOB) {
 
384
                        ++cp->recno;
 
385
                        break;
 
386
                }
 
387
                /* FALLTHROUGH */
 
388
        case DB_FIRST:
 
389
                flags = DB_NEXT;
 
390
                cp->recno = 1;
 
391
                break;
 
392
        case DB_PREV_NODUP:
 
393
                /*
 
394
                 * Recno databases don't have duplicates, set flags to DB_PREV
 
395
                 * and keep going.
 
396
                 */
 
397
                /* FALLTHROUGH */
 
398
        case DB_PREV:
 
399
                flags = DB_PREV;
 
400
                if (cp->recno != RECNO_OOB) {
 
401
                        if (cp->recno == 1) {
 
402
                                ret = DB_NOTFOUND;
 
403
                                goto err;
 
404
                        }
 
405
                        --cp->recno;
 
406
                        break;
 
407
                }
 
408
                /* FALLTHROUGH */
 
409
        case DB_LAST:
 
410
                flags = DB_PREV;
 
411
                if (((ret = __ram_update(dbc,
 
412
                    DB_MAX_RECORDS, 0)) != 0) && ret != DB_NOTFOUND)
 
413
                        goto err;
 
414
                if ((ret = __bam_nrecs(dbc, &cp->recno)) != 0)
 
415
                        goto err;
 
416
                if (cp->recno == 0) {
 
417
                        ret = DB_NOTFOUND;
 
418
                        goto err;
 
419
                }
 
420
                break;
 
421
        case DB_GET_BOTHC:
 
422
                /*
 
423
                 * If we're doing a join and these are offpage dups,
 
424
                 * we want to keep searching forward from after the
 
425
                 * current cursor position.  Increment the recno by 1,
 
426
                 * then proceed as for a DB_SET.
 
427
                 *
 
428
                 * Otherwise, we know there are no additional matching
 
429
                 * data, as recnos don't have dups.  return DB_NOTFOUND.
 
430
                 */
 
431
                if (F_ISSET(dbc, DBC_OPD)) {
 
432
                        cp->recno++;
 
433
                        break;
 
434
                }
 
435
                ret = DB_NOTFOUND;
 
436
                goto err;
 
437
                /* NOTREACHED */
 
438
        case DB_GET_BOTH:
 
439
                /*
 
440
                 * If we're searching a set of off-page dups, we start
 
441
                 * a new linear search from the first record.  Otherwise,
 
442
                 * we compare the single data item associated with the
 
443
                 * requested record for a match.
 
444
                 */
 
445
                if (F_ISSET(dbc, DBC_OPD)) {
 
446
                        cp->recno = 1;
 
447
                        break;
 
448
                }
 
449
                /* FALLTHROUGH */
 
450
        case DB_SET:
 
451
        case DB_SET_RANGE:
 
452
                if ((ret = __ram_getno(dbc, key, &cp->recno, 0)) != 0)
 
453
                        goto err;
 
454
                break;
 
455
        default:
 
456
                ret = __db_unknown_flag(dbp->dbenv, "__ram_c_get", flags);
 
457
                goto err;
 
458
        }
 
459
 
 
460
        /*
 
461
         * For DB_PREV, DB_LAST, DB_SET and DB_SET_RANGE, we have already
 
462
         * called __ram_update() to make sure sufficient records have been
 
463
         * read from the backing source file.  Do it now for DB_CURRENT (if
 
464
         * the current record was deleted we may need more records from the
 
465
         * backing file for a DB_CURRENT operation), DB_FIRST and DB_NEXT.
 
466
         * (We don't have to test for flags == DB_FIRST, because the switch
 
467
         * statement above re-set flags to DB_NEXT in that case.)
 
468
         */
 
469
        if ((flags == DB_NEXT || flags == DB_CURRENT) && ((ret =
 
470
            __ram_update(dbc, cp->recno, 0)) != 0) && ret != DB_NOTFOUND)
 
471
                goto err;
 
472
 
 
473
        for (;; ++cp->recno) {
 
474
                /* Search the tree for the record. */
 
475
                if ((ret = __bam_rsearch(dbc, &cp->recno,
 
476
                    F_ISSET(dbc, DBC_RMW) ? S_FIND_WR : S_FIND,
 
477
                    1, &exact)) != 0)
 
478
                        goto err;
 
479
                if (!exact) {
 
480
                        ret = DB_NOTFOUND;
 
481
                        goto err;
 
482
                }
 
483
 
 
484
                /*
 
485
                 * Copy the page into the cursor, discarding any lock we
 
486
                 * are currently holding.
 
487
                 */
 
488
                cp->page = cp->csp->page;
 
489
                cp->pgno = cp->csp->page->pgno;
 
490
                cp->indx = cp->csp->indx;
 
491
                (void)__TLPUT(dbc, cp->lock);
 
492
                cp->lock = cp->csp->lock;
 
493
                cp->lock_mode = cp->csp->lock_mode;
 
494
 
 
495
                /*
 
496
                 * If re-numbering records, the on-page deleted flag means this
 
497
                 * record was implicitly created.  If not re-numbering records,
 
498
                 * the on-page deleted flag means this record was implicitly
 
499
                 * created, or, it was deleted at some time.  Regardless, we
 
500
                 * skip such records if doing cursor next/prev operations or
 
501
                 * walking through off-page duplicates, and fail if they were
 
502
                 * requested explicitly by the application.
 
503
                 */
 
504
                if (B_DISSET(GET_BKEYDATA(cp->page, cp->indx)->type))
 
505
                        switch (flags) {
 
506
                        case DB_NEXT:
 
507
                        case DB_PREV:
 
508
                                (void)__bam_stkrel(dbc, STK_CLRDBC);
 
509
                                goto retry;
 
510
                        case DB_GET_BOTH:
 
511
                                /*
 
512
                                 * If we're an OPD tree, we don't care
 
513
                                 * about matching a record number on a
 
514
                                 * DB_GET_BOTH--everything belongs to the
 
515
                                 * same tree.  A normal recno should give
 
516
                                 * up and return DB_NOTFOUND if the matching
 
517
                                 * recno is deleted.
 
518
                                 */
 
519
                                if (F_ISSET(dbc, DBC_OPD)) {
 
520
                                        (void)__bam_stkrel(dbc, STK_CLRDBC);
 
521
                                        continue;
 
522
                                }
 
523
                                ret = DB_NOTFOUND;
 
524
                                goto err;
 
525
                        default:
 
526
                                ret = DB_KEYEMPTY;
 
527
                                goto err;
 
528
                        }
 
529
 
 
530
                if (flags == DB_GET_BOTH || flags == DB_GET_BOTHC) {
 
531
                        if ((ret = __bam_cmp(dbp, data,
 
532
                            cp->page, cp->indx, __bam_defcmp, &cmp)) != 0)
 
533
                                return (ret);
 
534
                        if (cmp == 0)
 
535
                                break;
 
536
                        if (!F_ISSET(dbc, DBC_OPD)) {
 
537
                                ret = DB_NOTFOUND;
 
538
                                goto err;
 
539
                        }
 
540
                        (void)__bam_stkrel(dbc, STK_CLRDBC);
 
541
                } else
 
542
                        break;
 
543
        }
 
544
 
 
545
        /* Return the key if the user didn't give us one. */
 
546
        if (!F_ISSET(dbc, DBC_OPD)) {
 
547
                if (flags != DB_SET && flags != DB_SET_RANGE)
 
548
                        ret = __db_retcopy(dbp,
 
549
                             key, &cp->recno, sizeof(cp->recno),
 
550
                             &dbc->rkey->data, &dbc->rkey->ulen);
 
551
                F_SET(key, DB_DBT_ISSET);
 
552
        }
 
553
 
 
554
        /* The cursor was reset, no further delete adjustment is necessary. */
 
555
err:    CD_CLR(cp);
 
556
 
 
557
        return (ret);
 
558
}
 
559
 
 
560
/*
 
561
 * __ram_c_put --
 
562
 *      Recno cursor->c_put function.
 
563
 *
 
564
 * PUBLIC: int __ram_c_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *));
 
565
 */
 
566
int
 
567
__ram_c_put(dbc, key, data, flags, pgnop)
 
568
        DBC *dbc;
 
569
        DBT *key, *data;
 
570
        u_int32_t flags;
 
571
        db_pgno_t *pgnop;
 
572
{
 
573
        BTREE_CURSOR *cp;
 
574
        DB *dbp;
 
575
        DB_LSN lsn;
 
576
        int exact, nc, ret, t_ret;
 
577
        u_int32_t iiflags;
 
578
        void *arg;
 
579
 
 
580
        COMPQUIET(pgnop, NULL);
 
581
 
 
582
        dbp = dbc->dbp;
 
583
        cp = (BTREE_CURSOR *)dbc->internal;
 
584
 
 
585
        /*
 
586
         * DB_KEYFIRST and DB_KEYLAST mean different things if they're
 
587
         * used in an off-page duplicate tree.  If we're an off-page
 
588
         * duplicate tree, they really mean "put at the beginning of the
 
589
         * tree" and "put at the end of the tree" respectively, so translate
 
590
         * them to something else.
 
591
         */
 
592
        if (F_ISSET(dbc, DBC_OPD))
 
593
                switch (flags) {
 
594
                case DB_KEYFIRST:
 
595
                        cp->recno = 1;
 
596
                        flags = DB_BEFORE;
 
597
                        break;
 
598
                case DB_KEYLAST:
 
599
                        if ((ret = __ram_add(dbc,
 
600
                            &cp->recno, data, DB_APPEND, 0)) != 0)
 
601
                                return (ret);
 
602
                        if (CURADJ_LOG(dbc) &&
 
603
                            (ret = __bam_rcuradj_log(dbp->dbenv,
 
604
                            dbc->txn, &lsn, 0, dbp->log_fileid, CA_ICURRENT,
 
605
                            cp->root, cp->recno, cp->order)))
 
606
                                return (ret);
 
607
                        return (0);
 
608
                }
 
609
 
 
610
        /*
 
611
         * Handle normal DB_KEYFIRST/DB_KEYLAST;  for a recno, which has
 
612
         * no duplicates, these are identical and mean "put the given
 
613
         * datum at the given recno".
 
614
         *
 
615
         * Note that the code here used to be in __ram_put;  now, we
 
616
         * go through the access-method-common __db_put function, which
 
617
         * handles DB_NOOVERWRITE, so we and __ram_add don't have to.
 
618
         */
 
619
        if (flags == DB_KEYFIRST || flags == DB_KEYLAST) {
 
620
                ret = __ram_getno(dbc, key, &cp->recno, 1);
 
621
                if (ret == 0 || ret == DB_NOTFOUND)
 
622
                        ret = __ram_add(dbc, &cp->recno, data, 0, 0);
 
623
                return (ret);
 
624
        }
 
625
 
 
626
        /*
 
627
         * If we're putting with a cursor that's marked C_DELETED, we need to
 
628
         * take special care;  the cursor doesn't "really" reference the item
 
629
         * corresponding to its current recno, but instead is "between" that
 
630
         * record and the current one.  Translate the actual insert into
 
631
         * DB_BEFORE, and let the __ram_ca work out the gory details of what
 
632
         * should wind up pointing where.
 
633
         */
 
634
        if (CD_ISSET(cp))
 
635
                iiflags = DB_BEFORE;
 
636
        else
 
637
                iiflags = flags;
 
638
 
 
639
split:  if ((ret = __bam_rsearch(dbc, &cp->recno, S_INSERT, 1, &exact)) != 0)
 
640
                goto err;
 
641
        /*
 
642
         * An inexact match is okay;  it just means we're one record past the
 
643
         * end, which is reasonable if we're marked deleted.
 
644
         */
 
645
        DB_ASSERT(exact || CD_ISSET(cp));
 
646
 
 
647
        cp->page = cp->csp->page;
 
648
        cp->pgno = cp->csp->page->pgno;
 
649
        cp->indx = cp->csp->indx;
 
650
 
 
651
        ret = __bam_iitem(dbc, key, data, iiflags, 0);
 
652
        t_ret = __bam_stkrel(dbc, STK_CLRDBC);
 
653
 
 
654
        if (t_ret != 0 && (ret == 0 || ret == DB_NEEDSPLIT))
 
655
                ret = t_ret;
 
656
        else if (ret == DB_NEEDSPLIT) {
 
657
                arg = &cp->recno;
 
658
                if ((ret = __bam_split(dbc, arg, NULL)) != 0)
 
659
                        goto err;
 
660
                goto split;
 
661
        }
 
662
        if (ret != 0)
 
663
                goto err;
 
664
 
 
665
        switch (flags) {                        /* Adjust the cursors. */
 
666
        case DB_AFTER:
 
667
                nc = __ram_ca(dbc, CA_IAFTER);
 
668
 
 
669
                /*
 
670
                 * We only need to adjust this cursor forward if we truly added
 
671
                 * the item after the current recno, rather than remapping it
 
672
                 * to DB_BEFORE.
 
673
                 */
 
674
                if (iiflags == DB_AFTER)
 
675
                        ++cp->recno;
 
676
 
 
677
                /* Only log if __ram_ca found any relevant cursors. */
 
678
                if (nc > 0 && CURADJ_LOG(dbc) &&
 
679
                    (ret = __bam_rcuradj_log(dbp->dbenv,
 
680
                    dbc->txn, &lsn, 0, dbp->log_fileid, CA_IAFTER,
 
681
                    cp->root, cp->recno, cp->order)) != 0)
 
682
                        goto err;
 
683
                break;
 
684
        case DB_BEFORE:
 
685
                nc = __ram_ca(dbc, CA_IBEFORE);
 
686
                --cp->recno;
 
687
 
 
688
                /* Only log if __ram_ca found any relevant cursors. */
 
689
                if (nc > 0 && CURADJ_LOG(dbc) &&
 
690
                    (ret = __bam_rcuradj_log(dbp->dbenv,
 
691
                    dbc->txn, &lsn, 0, dbp->log_fileid, CA_IBEFORE,
 
692
                    cp->root, cp->recno, cp->order)) != 0)
 
693
                        goto err;
 
694
                break;
 
695
        case DB_CURRENT:
 
696
                /*
 
697
                 * We only need to do an adjustment if we actually
 
698
                 * added an item, which we only would have done if the
 
699
                 * cursor was marked deleted.
 
700
                 *
 
701
                 * Only log if __ram_ca found any relevant cursors.
 
702
                 */
 
703
                if (CD_ISSET(cp) && __ram_ca(dbc, CA_ICURRENT) > 0 &&
 
704
                    CURADJ_LOG(dbc) && (ret = __bam_rcuradj_log(
 
705
                    dbp->dbenv, dbc->txn, &lsn, 0, dbp->log_fileid,
 
706
                    CA_ICURRENT, cp->root, cp->recno, cp->order)) != 0)
 
707
                        goto err;
 
708
                break;
 
709
        }
 
710
 
 
711
        /* Return the key if we've created a new record. */
 
712
        if (!F_ISSET(dbc, DBC_OPD) && (flags == DB_AFTER || flags == DB_BEFORE))
 
713
                ret = __db_retcopy(dbp, key, &cp->recno,
 
714
                    sizeof(cp->recno), &dbc->rkey->data, &dbc->rkey->ulen);
 
715
 
 
716
        /* The cursor was reset, no further delete adjustment is necessary. */
 
717
err:    CD_CLR(cp);
 
718
 
 
719
        return (ret);
 
720
}
 
721
 
 
722
/*
 
723
 * __ram_ca --
 
724
 *      Adjust cursors.  Returns the number of relevant cursors.
 
725
 *
 
726
 * PUBLIC: int __ram_ca __P((DBC *, ca_recno_arg));
 
727
 */
 
728
int
 
729
__ram_ca(dbc_arg, op)
 
730
        DBC *dbc_arg;
 
731
        ca_recno_arg op;
 
732
{
 
733
        BTREE_CURSOR *cp, *cp_arg;
 
734
        DB *dbp, *ldbp;
 
735
        DB_ENV *dbenv;
 
736
        DBC *dbc;
 
737
        db_recno_t recno;
 
738
        int adjusted, found;
 
739
        u_int32_t order;
 
740
 
 
741
        dbp = dbc_arg->dbp;
 
742
        dbenv = dbp->dbenv;
 
743
        cp_arg = (BTREE_CURSOR *)dbc_arg->internal;
 
744
        recno = cp_arg->recno;
 
745
 
 
746
        found = 0;
 
747
 
 
748
        /*
 
749
         * It only makes sense to adjust cursors if we're a renumbering
 
750
         * recno;  we should only be called if this is one.
 
751
         */
 
752
        DB_ASSERT(F_ISSET(cp_arg, C_RENUMBER));
 
753
 
 
754
        MUTEX_THREAD_LOCK(dbenv, dbenv->dblist_mutexp);
 
755
        /*
 
756
         * Adjust the cursors.  See the comment in __bam_ca_delete().
 
757
         */
 
758
        /*
 
759
         * If we're doing a delete, we need to find the highest
 
760
         * order of any cursor currently pointing at this item,
 
761
         * so we can assign a higher order to the newly deleted
 
762
         * cursor.  Unfortunately, this requires a second pass through
 
763
         * the cursor list.
 
764
         */
 
765
        if (op == CA_DELETE) {
 
766
                order = 1;
 
767
                for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
 
768
                    ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
 
769
                    ldbp = LIST_NEXT(ldbp, dblistlinks)) {
 
770
                        MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
 
771
                        for (dbc = TAILQ_FIRST(&ldbp->active_queue);
 
772
                            dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
 
773
                                cp = (BTREE_CURSOR *)dbc->internal;
 
774
                                if (cp_arg->root == cp->root &&
 
775
                                    recno == cp->recno && CD_ISSET(cp) &&
 
776
                                    order <= cp->order)
 
777
                                        order = cp->order + 1;
 
778
                        }
 
779
                        MUTEX_THREAD_UNLOCK(dbenv, dbp->mutexp);
 
780
                }
 
781
        } else
 
782
                order = INVALID_ORDER;
 
783
 
 
784
        /* Now go through and do the actual adjustments. */
 
785
        for (ldbp = __dblist_get(dbenv, dbp->adj_fileid);
 
786
            ldbp != NULL && ldbp->adj_fileid == dbp->adj_fileid;
 
787
            ldbp = LIST_NEXT(ldbp, dblistlinks)) {
 
788
                MUTEX_THREAD_LOCK(dbenv, dbp->mutexp);
 
789
                for (dbc = TAILQ_FIRST(&ldbp->active_queue);
 
790
                    dbc != NULL; dbc = TAILQ_NEXT(dbc, links)) {
 
791
                        cp = (BTREE_CURSOR *)dbc->internal;
 
792
                        if (cp_arg->root != cp->root)
 
793
                                continue;
 
794
                        ++found;
 
795
                        adjusted = 0;
 
796
                        switch (op) {
 
797
                        case CA_DELETE:
 
798
                                if (recno < cp->recno) {
 
799
                                        --cp->recno;
 
800
                                        /*
 
801
                                         * If the adjustment made them equal,
 
802
                                         * we have to merge the orders.
 
803
                                         */
 
804
                                        if (recno == cp->recno && CD_ISSET(cp))
 
805
                                                cp->order += order;
 
806
                                } else if (recno == cp->recno &&
 
807
                                    !CD_ISSET(cp)) {
 
808
                                        CD_SET(cp);
 
809
                                        cp->order = order;
 
810
                                }
 
811
                                break;
 
812
                        case CA_IBEFORE:
 
813
                                /*
 
814
                                 * IBEFORE is just like IAFTER, except that we
 
815
                                 * adjust cursors on the current record too.
 
816
                                 */
 
817
                                if (C_EQUAL(cp_arg, cp)) {
 
818
                                        ++cp->recno;
 
819
                                        adjusted = 1;
 
820
                                }
 
821
                                goto iafter;
 
822
                        case CA_ICURRENT:
 
823
 
 
824
                                /*
 
825
                                 * If the original cursor wasn't deleted, we
 
826
                                 * just did a replacement and so there's no
 
827
                                 * need to adjust anything--we shouldn't have
 
828
                                 * gotten this far.  Otherwise, we behave
 
829
                                 * much like an IAFTER, except that all
 
830
                                 * cursors pointing to the current item get
 
831
                                 * marked undeleted and point to the new
 
832
                                 * item.
 
833
                                 */
 
834
                                DB_ASSERT(CD_ISSET(cp_arg));
 
835
                                if (C_EQUAL(cp_arg, cp)) {
 
836
                                        CD_CLR(cp);
 
837
                                        break;
 
838
                                }
 
839
                                /* FALLTHROUGH */
 
840
                        case CA_IAFTER:
 
841
iafter:                         if (!adjusted && C_LESSTHAN(cp_arg, cp)) {
 
842
                                        ++cp->recno;
 
843
                                        adjusted = 1;
 
844
                                }
 
845
                                if (recno == cp->recno && adjusted)
 
846
                                        /*
 
847
                                         * If we've moved this cursor's recno,
 
848
                                         * split its order number--i.e.,
 
849
                                         * decrement it by enough so that
 
850
                                         * the lowest cursor moved has order 1.
 
851
                                         * cp_arg->order is the split point,
 
852
                                         * so decrement by one less than that.
 
853
                                         */
 
854
                                        cp->order -= (cp_arg->order - 1);
 
855
                                break;
 
856
                        }
 
857
                }
 
858
                MUTEX_THREAD_UNLOCK(dbp->dbenv, dbp->mutexp);
 
859
        }
 
860
        MUTEX_THREAD_UNLOCK(dbenv, dbenv->dblist_mutexp);
 
861
 
 
862
        return (found);
 
863
}
 
864
 
 
865
/*
 
866
 * __ram_getno --
 
867
 *      Check the user's record number, and make sure we've seen it.
 
868
 *
 
869
 * PUBLIC: int __ram_getno __P((DBC *, const DBT *, db_recno_t *, int));
 
870
 */
 
871
int
 
872
__ram_getno(dbc, key, rep, can_create)
 
873
        DBC *dbc;
 
874
        const DBT *key;
 
875
        db_recno_t *rep;
 
876
        int can_create;
 
877
{
 
878
        DB *dbp;
 
879
        db_recno_t recno;
 
880
 
 
881
        dbp = dbc->dbp;
 
882
 
 
883
        /* Check the user's record number. */
 
884
        if ((recno = *(db_recno_t *)key->data) == 0) {
 
885
                __db_err(dbp->dbenv, "illegal record number of 0");
 
886
                return (EINVAL);
 
887
        }
 
888
        if (rep != NULL)
 
889
                *rep = recno;
 
890
 
 
891
        /*
 
892
         * Btree can neither create records nor read them in.  Recno can
 
893
         * do both, see if we can find the record.
 
894
         */
 
895
        return (dbc->dbtype == DB_RECNO ?
 
896
            __ram_update(dbc, recno, can_create) : 0);
 
897
}
 
898
 
 
899
/*
 
900
 * __ram_update --
 
901
 *      Ensure the tree has records up to and including the specified one.
 
902
 */
 
903
static int
 
904
__ram_update(dbc, recno, can_create)
 
905
        DBC *dbc;
 
906
        db_recno_t recno;
 
907
        int can_create;
 
908
{
 
909
        BTREE *t;
 
910
        DB *dbp;
 
911
        DBT *rdata;
 
912
        db_recno_t nrecs;
 
913
        int ret;
 
914
 
 
915
        dbp = dbc->dbp;
 
916
        t = dbp->bt_internal;
 
917
 
 
918
        /*
 
919
         * If we can't create records and we've read the entire backing input
 
920
         * file, we're done.
 
921
         */
 
922
        if (!can_create && t->re_eof)
 
923
                return (0);
 
924
 
 
925
        /*
 
926
         * If we haven't seen this record yet, try to get it from the original
 
927
         * file.
 
928
         */
 
929
        if ((ret = __bam_nrecs(dbc, &nrecs)) != 0)
 
930
                return (ret);
 
931
        if (!t->re_eof && recno > nrecs) {
 
932
                if ((ret = __ram_sread(dbc, recno)) != 0 && ret != DB_NOTFOUND)
 
933
                        return (ret);
 
934
                if ((ret = __bam_nrecs(dbc, &nrecs)) != 0)
 
935
                        return (ret);
 
936
        }
 
937
 
 
938
        /*
 
939
         * If we can create records, create empty ones up to the requested
 
940
         * record.
 
941
         */
 
942
        if (!can_create || recno <= nrecs + 1)
 
943
                return (0);
 
944
 
 
945
        rdata = &dbc->my_rdata;
 
946
        rdata->flags = 0;
 
947
        rdata->size = 0;
 
948
 
 
949
        while (recno > ++nrecs)
 
950
                if ((ret = __ram_add(dbc,
 
951
                    &nrecs, rdata, 0, BI_DELETED)) != 0)
 
952
                        return (ret);
 
953
        return (0);
 
954
}
 
955
 
 
956
/*
 
957
 * __ram_source --
 
958
 *      Load information about the backing file.
 
959
 */
 
960
static int
 
961
__ram_source(dbp)
 
962
        DB *dbp;
 
963
{
 
964
        BTREE *t;
 
965
        char *source;
 
966
        int ret;
 
967
 
 
968
        t = dbp->bt_internal;
 
969
 
 
970
        /* Find the real name, and swap out the one we had before. */
 
971
        if ((ret = __db_appname(dbp->dbenv,
 
972
            DB_APP_DATA, NULL, t->re_source, 0, NULL, &source)) != 0)
 
973
                return (ret);
 
974
        __os_freestr(dbp->dbenv, t->re_source);
 
975
        t->re_source = source;
 
976
 
 
977
        /*
 
978
         * !!!
 
979
         * It's possible that the backing source file is read-only.  We don't
 
980
         * much care other than we'll complain if there are any modifications
 
981
         * when it comes time to write the database back to the source.
 
982
         */
 
983
        if ((t->re_fp = fopen(t->re_source, "r")) == NULL) {
 
984
                ret = errno;
 
985
                __db_err(dbp->dbenv, "%s: %s", t->re_source, db_strerror(ret));
 
986
                return (ret);
 
987
        }
 
988
 
 
989
        t->re_eof = 0;
 
990
        return (0);
 
991
}
 
992
 
 
993
/*
 
994
 * __ram_writeback --
 
995
 *      Rewrite the backing file.
 
996
 *
 
997
 * PUBLIC: int __ram_writeback __P((DB *));
 
998
 */
 
999
int
 
1000
__ram_writeback(dbp)
 
1001
        DB *dbp;
 
1002
{
 
1003
        BTREE *t;
 
1004
        DB_ENV *dbenv;
 
1005
        DBC *dbc;
 
1006
        DBT key, data;
 
1007
        FILE *fp;
 
1008
        db_recno_t keyno;
 
1009
        int ret, t_ret;
 
1010
        u_int8_t delim, *pad;
 
1011
 
 
1012
        t = dbp->bt_internal;
 
1013
        dbenv = dbp->dbenv;
 
1014
        fp = NULL;
 
1015
 
 
1016
        /* If the file wasn't modified, we're done. */
 
1017
        if (!t->re_modified)
 
1018
                return (0);
 
1019
 
 
1020
        /* If there's no backing source file, we're done. */
 
1021
        if (t->re_source == NULL) {
 
1022
                t->re_modified = 0;
 
1023
                return (0);
 
1024
        }
 
1025
 
 
1026
        /* Allocate a cursor. */
 
1027
        if ((ret = dbp->cursor(dbp, NULL, &dbc, 0)) != 0)
 
1028
                return (ret);
 
1029
 
 
1030
        /*
 
1031
         * Read any remaining records into the tree.
 
1032
         *
 
1033
         * !!!
 
1034
         * This is why we can't support transactions when applications specify
 
1035
         * backing (re_source) files.  At this point we have to read in the
 
1036
         * rest of the records from the file so that we can write all of the
 
1037
         * records back out again, which could modify a page for which we'd
 
1038
         * have to log changes and which we don't have locked.  This could be
 
1039
         * partially fixed by taking a snapshot of the entire file during the
 
1040
         * DB->open as DB->open is transaction protected.  But, if a checkpoint
 
1041
         * occurs then, the part of the log holding the copy of the file could
 
1042
         * be discarded, and that would make it impossible to recover in the
 
1043
         * face of disaster.  This could all probably be fixed, but it would
 
1044
         * require transaction protecting the backing source file.
 
1045
         *
 
1046
         * XXX
 
1047
         * This could be made to work now that we have transactions protecting
 
1048
         * file operations.  Margo has specifically asked for the privilege of
 
1049
         * doing this work.
 
1050
         */
 
1051
        if ((ret =
 
1052
            __ram_update(dbc, DB_MAX_RECORDS, 0)) != 0 && ret != DB_NOTFOUND)
 
1053
                return (ret);
 
1054
 
 
1055
        /*
 
1056
         * Close any existing file handle and re-open the file, truncating it.
 
1057
         */
 
1058
        if (t->re_fp != NULL) {
 
1059
                if (fclose(t->re_fp) != 0) {
 
1060
                        ret = errno;
 
1061
                        goto err;
 
1062
                }
 
1063
                t->re_fp = NULL;
 
1064
        }
 
1065
        if ((fp = fopen(t->re_source, "w")) == NULL) {
 
1066
                ret = errno;
 
1067
                __db_err(dbenv, "%s: %s", t->re_source, db_strerror(ret));
 
1068
                goto err;
 
1069
        }
 
1070
 
 
1071
        /*
 
1072
         * We step through the records, writing each one out.  Use the record
 
1073
         * number and the dbp->get() function, instead of a cursor, so we find
 
1074
         * and write out "deleted" or non-existent records.
 
1075
         */
 
1076
        memset(&key, 0, sizeof(key));
 
1077
        memset(&data, 0, sizeof(data));
 
1078
        key.size = sizeof(db_recno_t);
 
1079
        key.data = &keyno;
 
1080
 
 
1081
        /*
 
1082
         * We'll need the delimiter if we're doing variable-length records,
 
1083
         * and the pad character if we're doing fixed-length records.
 
1084
         */
 
1085
        delim = t->re_delim;
 
1086
        if (F_ISSET(dbp, DB_RE_FIXEDLEN)) {
 
1087
                if ((ret = __os_malloc(dbenv, t->re_len, &pad)) != 0)
 
1088
                        goto err;
 
1089
                memset(pad, t->re_pad, t->re_len);
 
1090
        } else
 
1091
                COMPQUIET(pad, NULL);
 
1092
        for (keyno = 1;; ++keyno) {
 
1093
                switch (ret = dbp->get(dbp, NULL, &key, &data, 0)) {
 
1094
                case 0:
 
1095
                        if (fwrite(data.data, 1, data.size, fp) != data.size)
 
1096
                                goto write_err;
 
1097
                        break;
 
1098
                case DB_KEYEMPTY:
 
1099
                        if (F_ISSET(dbp, DB_RE_FIXEDLEN) &&
 
1100
                            fwrite(pad, 1, t->re_len, fp) != t->re_len)
 
1101
                                goto write_err;
 
1102
                        break;
 
1103
                case DB_NOTFOUND:
 
1104
                        ret = 0;
 
1105
                        goto done;
 
1106
                }
 
1107
                if (!F_ISSET(dbp, DB_RE_FIXEDLEN) &&
 
1108
                    fwrite(&delim, 1, 1, fp) != 1) {
 
1109
write_err:              ret = errno;
 
1110
                        __db_err(dbp->dbenv,
 
1111
                            "%s: write failed to backing file: %s",
 
1112
                            t->re_source, strerror(ret));
 
1113
                        goto err;
 
1114
                }
 
1115
        }
 
1116
 
 
1117
err:
 
1118
done:   /* Close the file descriptor. */
 
1119
        if (fp != NULL && fclose(fp) != 0) {
 
1120
                if (ret == 0)
 
1121
                        ret = errno;
 
1122
                __db_err(dbenv, "%s: %s", t->re_source, db_strerror(errno));
 
1123
        }
 
1124
 
 
1125
        /* Discard the cursor. */
 
1126
        if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
 
1127
                ret = t_ret;
 
1128
 
 
1129
        if (ret == 0)
 
1130
                t->re_modified = 0;
 
1131
 
 
1132
        return (ret);
 
1133
}
 
1134
 
 
1135
/*
 
1136
 * __ram_sread --
 
1137
 *      Read records from a source file.
 
1138
 */
 
1139
static int
 
1140
__ram_sread(dbc, top)
 
1141
        DBC *dbc;
 
1142
        db_recno_t top;
 
1143
{
 
1144
        BTREE *t;
 
1145
        DB *dbp;
 
1146
        DBT data, *rdata;
 
1147
        db_recno_t recno;
 
1148
        size_t len;
 
1149
        int ch, ret, was_modified;
 
1150
 
 
1151
        t = dbc->dbp->bt_internal;
 
1152
        dbp = dbc->dbp;
 
1153
        was_modified = t->re_modified;
 
1154
 
 
1155
        if ((ret = __bam_nrecs(dbc, &recno)) != 0)
 
1156
                return (ret);
 
1157
 
 
1158
        /*
 
1159
         * Use the record key return memory, it's only a short-term use.
 
1160
         * The record data return memory is used by __bam_iitem, which
 
1161
         * we'll indirectly call, so use the key so as not to collide.
 
1162
         */
 
1163
        len = F_ISSET(dbp, DB_RE_FIXEDLEN) ? t->re_len : 256;
 
1164
        rdata = &dbc->my_rkey;
 
1165
        if (rdata->ulen < len) {
 
1166
                if ((ret = __os_realloc(
 
1167
                    dbp->dbenv, len, &rdata->data)) != 0) {
 
1168
                        rdata->ulen = 0;
 
1169
                        rdata->data = NULL;
 
1170
                        return (ret);
 
1171
                }
 
1172
                rdata->ulen = len;
 
1173
        }
 
1174
 
 
1175
        memset(&data, 0, sizeof(data));
 
1176
        while (recno < top) {
 
1177
                data.data = rdata->data;
 
1178
                data.size = 0;
 
1179
                if (F_ISSET(dbp, DB_RE_FIXEDLEN))
 
1180
                        for (len = t->re_len; len > 0; --len) {
 
1181
                                if ((ch = getc(t->re_fp)) == EOF) {
 
1182
                                        if (data.size == 0)
 
1183
                                                goto eof;
 
1184
                                        break;
 
1185
                                }
 
1186
                                ((u_int8_t *)data.data)[data.size++] = ch;
 
1187
                        }
 
1188
                else
 
1189
                        for (;;) {
 
1190
                                if ((ch = getc(t->re_fp)) == EOF) {
 
1191
                                        if (data.size == 0)
 
1192
                                                goto eof;
 
1193
                                        break;
 
1194
                                }
 
1195
                                if (ch == t->re_delim)
 
1196
                                        break;
 
1197
 
 
1198
                                ((u_int8_t *)data.data)[data.size++] = ch;
 
1199
                                if (data.size == rdata->ulen) {
 
1200
                                        if ((ret = __os_realloc(dbp->dbenv,
 
1201
                                            rdata->ulen *= 2,
 
1202
                                            &rdata->data)) != 0) {
 
1203
                                                rdata->ulen = 0;
 
1204
                                                rdata->data = NULL;
 
1205
                                                return (ret);
 
1206
                                        } else
 
1207
                                                data.data = rdata->data;
 
1208
                                }
 
1209
                        }
 
1210
 
 
1211
                /*
 
1212
                 * Another process may have read this record from the input
 
1213
                 * file and stored it into the database already, in which
 
1214
                 * case we don't need to repeat that operation.  We detect
 
1215
                 * this by checking if the last record we've read is greater
 
1216
                 * or equal to the number of records in the database.
 
1217
                 */
 
1218
                if (t->re_last >= recno) {
 
1219
                        ++recno;
 
1220
                        if ((ret = __ram_add(dbc, &recno, &data, 0, 0)) != 0)
 
1221
                                goto err;
 
1222
                }
 
1223
                ++t->re_last;
 
1224
        }
 
1225
 
 
1226
        if (0) {
 
1227
eof:            t->re_eof = 1;
 
1228
                ret = DB_NOTFOUND;
 
1229
        }
 
1230
err:    if (!was_modified)
 
1231
                t->re_modified = 0;
 
1232
 
 
1233
        return (ret);
 
1234
}
 
1235
 
 
1236
/*
 
1237
 * __ram_add --
 
1238
 *      Add records into the tree.
 
1239
 */
 
1240
static int
 
1241
__ram_add(dbc, recnop, data, flags, bi_flags)
 
1242
        DBC *dbc;
 
1243
        db_recno_t *recnop;
 
1244
        DBT *data;
 
1245
        u_int32_t flags, bi_flags;
 
1246
{
 
1247
        BTREE_CURSOR *cp;
 
1248
        int exact, ret, stack;
 
1249
 
 
1250
        cp = (BTREE_CURSOR *)dbc->internal;
 
1251
 
 
1252
retry:  /* Find the slot for insertion. */
 
1253
        if ((ret = __bam_rsearch(dbc, recnop,
 
1254
            S_INSERT | (flags == DB_APPEND ? S_APPEND : 0), 1, &exact)) != 0)
 
1255
                return (ret);
 
1256
        stack = 1;
 
1257
        cp->page = cp->csp->page;
 
1258
        cp->pgno = cp->csp->page->pgno;
 
1259
        cp->indx = cp->csp->indx;
 
1260
 
 
1261
        /*
 
1262
         * The application may modify the data based on the selected record
 
1263
         * number.
 
1264
         */
 
1265
        if (flags == DB_APPEND && dbc->dbp->db_append_recno != NULL &&
 
1266
            (ret = dbc->dbp->db_append_recno(dbc->dbp, data, *recnop)) != 0)
 
1267
                goto err;
 
1268
 
 
1269
        /*
 
1270
         * Select the arguments for __bam_iitem() and do the insert.  If the
 
1271
         * key is an exact match, or we're replacing the data item with a
 
1272
         * new data item, replace the current item.  If the key isn't an exact
 
1273
         * match, we're inserting a new key/data pair, before the search
 
1274
         * location.
 
1275
         */
 
1276
        switch (ret = __bam_iitem(dbc,
 
1277
            NULL, data, exact ? DB_CURRENT : DB_BEFORE, bi_flags)) {
 
1278
        case 0:
 
1279
                /*
 
1280
                 * Don't adjust anything.
 
1281
                 *
 
1282
                 * If we inserted a record, no cursors need adjusting because
 
1283
                 * the only new record it's possible to insert is at the very
 
1284
                 * end of the tree.  The necessary adjustments to the internal
 
1285
                 * page counts were made by __bam_iitem().
 
1286
                 *
 
1287
                 * If we overwrote a record, no cursors need adjusting because
 
1288
                 * future DBcursor->get calls will simply return the underlying
 
1289
                 * record (there's no adjustment made for the DB_CURRENT flag
 
1290
                 * when a cursor get operation immediately follows a cursor
 
1291
                 * delete operation, and the normal adjustment for the DB_NEXT
 
1292
                 * flag is still correct).
 
1293
                 */
 
1294
                break;
 
1295
        case DB_NEEDSPLIT:
 
1296
                /* Discard the stack of pages and split the page. */
 
1297
                (void)__bam_stkrel(dbc, STK_CLRDBC);
 
1298
                stack = 0;
 
1299
 
 
1300
                if ((ret = __bam_split(dbc, recnop, NULL)) != 0)
 
1301
                        goto err;
 
1302
 
 
1303
                goto retry;
 
1304
                /* NOTREACHED */
 
1305
        default:
 
1306
                goto err;
 
1307
        }
 
1308
 
 
1309
err:    if (stack)
 
1310
                __bam_stkrel(dbc, STK_CLRDBC);
 
1311
 
 
1312
        return (ret);
 
1313
}