source: trunk/third/evolution-data-server/libdb/dbreg/dbreg_util.c @ 21189

Revision 21189, 19.5 KB checked in by ghudson, 20 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r21188, which included commits to RCS files with non-trunk default branches.
Line 
1/*-
2 * See the file LICENSE for redistribution information.
3 *
4 * Copyright (c) 1997-2002
5 *      Sleepycat Software.  All rights reserved.
6 */
7
8#include "db_config.h"
9
10#ifndef lint
11static const char revid[] = "$Id: dbreg_util.c,v 1.1.1.1 2004-12-17 17:26:59 ghudson Exp $";
12#endif /* not lint */
13
14#ifndef NO_SYSTEM_INCLUDES
15#include <sys/types.h>
16#include <string.h>
17#endif
18
19#include "db_int.h"
20#include "dbinc/db_page.h"
21#include "dbinc/db_am.h"
22#include "dbinc/log.h"
23#include "dbinc/txn.h"
24
25static int __dbreg_check_master __P((DB_ENV *, u_int8_t *, char *));
26
27/*
28 * __dbreg_add_dbentry --
29 *      Adds a DB entry to the dbreg DB entry table.
30 *
31 * PUBLIC: int __dbreg_add_dbentry __P((DB_ENV *, DB_LOG *, DB *, int32_t));
32 */
33int
34__dbreg_add_dbentry(dbenv, dblp, dbp, ndx)
35        DB_ENV *dbenv;
36        DB_LOG *dblp;
37        DB *dbp;
38        int32_t ndx;
39{
40        int32_t i;
41        int ret;
42
43        ret = 0;
44
45        MUTEX_THREAD_LOCK(dbenv, dblp->mutexp);
46
47        /*
48         * Check if we need to grow the table.  Note, ndx is 0-based (the
49         * index into the DB entry table) an dbentry_cnt is 1-based, the
50         * number of available slots.
51         */
52        if (dblp->dbentry_cnt <= ndx) {
53                if ((ret = __os_realloc(dbenv,
54                    (ndx + DB_GROW_SIZE) * sizeof(DB_ENTRY),
55                    &dblp->dbentry)) != 0)
56                        goto err;
57
58                /* Initialize the new entries. */
59                for (i = dblp->dbentry_cnt; i < ndx + DB_GROW_SIZE; i++) {
60                        dblp->dbentry[i].dbp = NULL;
61                        dblp->dbentry[i].deleted = 0;
62                }
63                dblp->dbentry_cnt = i;
64        }
65
66        DB_ASSERT(dblp->dbentry[ndx].dbp == NULL);
67        dblp->dbentry[ndx].deleted = dbp == NULL;
68        dblp->dbentry[ndx].dbp = dbp;
69
70err:    MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
71        return (ret);
72}
73
74/*
75 * __dbreg_rem_dbentry
76 *      Remove an entry from the DB entry table.
77 *
78 * PUBLIC: void __dbreg_rem_dbentry __P((DB_LOG *, int32_t));
79 */
80void
81__dbreg_rem_dbentry(dblp, ndx)
82        DB_LOG *dblp;
83        int32_t ndx;
84{
85        MUTEX_THREAD_LOCK(dblp->dbenv, dblp->mutexp);
86        dblp->dbentry[ndx].dbp = NULL;
87        dblp->dbentry[ndx].deleted = 0;
88        MUTEX_THREAD_UNLOCK(dblp->dbenv, dblp->mutexp);
89}
90
91/*
92 * __dbreg_open_files --
93 *      Put a LOG_CHECKPOINT log record for each open database.
94 *
95 * PUBLIC: int __dbreg_open_files __P((DB_ENV *));
96 */
97int
98__dbreg_open_files(dbenv)
99        DB_ENV *dbenv;
100{
101        DB_LOG *dblp;
102        DB_LSN r_unused;
103        DBT *dbtp, fid_dbt, t;
104        FNAME *fnp;
105        LOG *lp;
106        int ret;
107
108        dblp = dbenv->lg_handle;
109        lp = dblp->reginfo.primary;
110
111        ret = 0;
112
113        MUTEX_LOCK(dbenv, &lp->fq_mutex);
114
115        for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
116            fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
117                if (fnp->name_off == INVALID_ROFF)
118                        dbtp = NULL;
119                else {
120                        memset(&t, 0, sizeof(t));
121                        t.data = R_ADDR(&dblp->reginfo, fnp->name_off);
122                        t.size = (u_int32_t)strlen(t.data) + 1;
123                        dbtp = &t;
124                }
125                memset(&fid_dbt, 0, sizeof(fid_dbt));
126                fid_dbt.data = fnp->ufid;
127                fid_dbt.size = DB_FILE_ID_LEN;
128                /*
129                 * Output LOG_CHECKPOINT records which will be
130                 * processed during the OPENFILES pass of recovery.
131                 * At the end of recovery we want to output the
132                 * files that were open so that a future recovery
133                 * run will have the correct files open during
134                 * a backward pass.  For this we output LOG_RCLOSE
135                 * records so that the files will be closed on
136                 * the forward pass.
137                 */
138                if ((ret = __dbreg_register_log(dbenv,
139                    NULL, &r_unused, 0,
140                    F_ISSET(dblp, DBLOG_RECOVER) ? LOG_RCLOSE : LOG_CHECKPOINT,
141                    dbtp, &fid_dbt, fnp->id, fnp->s_type, fnp->meta_pgno,
142                    TXN_INVALID)) != 0)
143                        break;
144        }
145
146        MUTEX_UNLOCK(dbenv, &lp->fq_mutex);
147
148        return (ret);
149}
150
151/*
152 * __dbreg_close_files --
153 *      Close files that were opened by the recovery daemon.  We sync the
154 *      file, unless its mpf pointer has been NULLed by a db_remove or
155 *      db_rename.  We may not have flushed the log_register record that
156 *      closes the file.
157 *
158 * PUBLIC: int __dbreg_close_files __P((DB_ENV *));
159 */
160int
161__dbreg_close_files(dbenv)
162        DB_ENV *dbenv;
163{
164        DB_LOG *dblp;
165        DB *dbp;
166        int ret, t_ret;
167        int32_t i;
168
169        /* If we haven't initialized logging, we have nothing to do. */
170        if (!LOGGING_ON(dbenv))
171                return (0);
172
173        dblp = dbenv->lg_handle;
174        ret = 0;
175        MUTEX_THREAD_LOCK(dbenv, dblp->mutexp);
176        for (i = 0; i < dblp->dbentry_cnt; i++) {
177                /* We only want to close dbps that recovery opened. */
178                if ((dbp = dblp->dbentry[i].dbp) != NULL &&
179                    F_ISSET(dbp, DB_AM_RECOVER)) {
180                        /*
181                         * It's unsafe to call DB->close while holding the
182                         * thread lock, because we'll call __dbreg_rem_dbentry
183                         * and grab it again.
184                         *
185                         * Just drop it.  Since dbreg ids go monotonically
186                         * upward, concurrent opens should be safe, and the
187                         * user should have no business closing files while
188                         * we're in this loop anyway--we're in the process of
189                         * making all outstanding dbps invalid.
190                         */
191                        MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
192                        if ((t_ret = dbp->close(dbp,
193                            dbp->mpf == NULL ? DB_NOSYNC : 0)) != 0 && ret == 0)
194                                ret = t_ret;
195                        MUTEX_THREAD_LOCK(dbenv, dblp->mutexp);
196                }
197                dblp->dbentry[i].deleted = 0;
198                dblp->dbentry[i].dbp = NULL;
199        }
200        MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
201        return (ret);
202}
203
204/*
205 * __dbreg_nofiles --
206 *      Check that there are no open files in the process local table.
207 *      Returns 0 if there are no files and EINVAL if there are any.
208 *
209 * PUBLIC: int __dbreg_nofiles __P((DB_ENV *));
210 */
211int
212__dbreg_nofiles(dbenv)
213        DB_ENV *dbenv;
214{
215        DB *dbp;
216        DB_LOG *dblp;
217        int ret;
218        int32_t i;
219
220        /* If we haven't initialized logging, we have nothing to do. */
221        if (!LOGGING_ON(dbenv))
222                return (0);
223
224        dblp = dbenv->lg_handle;
225        ret = 0;
226        MUTEX_THREAD_LOCK(dbenv, dblp->mutexp);
227        for (i = 0; i < dblp->dbentry_cnt; i++) {
228                if ((dbp = dblp->dbentry[i].dbp) != NULL &&
229                    !F_ISSET(dbp, DB_AM_RECOVER)) {
230                        ret = EINVAL;
231                        break;
232                }
233        }
234        MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
235        return (ret);
236}
237
238/*
239 * __dbreg_id_to_db --
240 *      Return the DB corresponding to the specified dbreg id.
241 *
242 * PUBLIC: int __dbreg_id_to_db __P((DB_ENV *, DB_TXN *, DB **, int32_t, int));
243 */
244int
245__dbreg_id_to_db(dbenv, txn, dbpp, ndx, inc)
246        DB_ENV *dbenv;
247        DB_TXN *txn;
248        DB **dbpp;
249        int32_t ndx;
250        int inc;
251{
252        return (__dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, 1));
253}
254
255/*
256 * __dbreg_id_to_db_int --
257 *      Return the DB corresponding to the specified dbreg id.  The internal
258 * version takes a final parameter that indicates whether we should attempt
259 * to open the file if no mapping is found.  During recovery, the recovery
260 * routines all want to try to open the file (and this is called from
261 * __dbreg_id_to_db), however, if we have a multi-process environment where
262 * some processes may not have the files open (e.g., XA), then we also get
263 * called from __dbreg_assign_id and it's OK if there is no mapping.
264 *
265 * PUBLIC: int __dbreg_id_to_db_int __P((DB_ENV *,
266 * PUBLIC:     DB_TXN *, DB **, int32_t, int, int));
267 */
268int
269__dbreg_id_to_db_int(dbenv, txn, dbpp, ndx, inc, tryopen)
270        DB_ENV *dbenv;
271        DB_TXN *txn;
272        DB **dbpp;
273        int32_t ndx;
274        int inc, tryopen;
275{
276        DB_LOG *dblp;
277        FNAME *fname;
278        int ret;
279        char *name;
280
281        ret = 0;
282        dblp = dbenv->lg_handle;
283        COMPQUIET(inc, 0);
284
285        MUTEX_THREAD_LOCK(dbenv, dblp->mutexp);
286
287        /*
288         * Under XA, a process different than the one issuing DB operations
289         * may abort a transaction.  In this case, the "recovery" routines
290         * are run by a process that does not necessarily have the file open,
291         * so we we must open the file explicitly.
292         */
293        if (ndx >= dblp->dbentry_cnt ||
294            (!dblp->dbentry[ndx].deleted && dblp->dbentry[ndx].dbp == NULL)) {
295                if (!tryopen || F_ISSET(dblp, DBLOG_RECOVER)) {
296                        ret = ENOENT;
297                        goto err;
298                }
299
300                /*
301                 * __dbreg_id_to_fname acquires the region's fq_mutex,
302                 * which we can't safely acquire while we hold the thread lock.
303                 * We no longer need it anyway--the dbentry table didn't
304                 * have what we needed.
305                 */
306                MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
307
308                if (__dbreg_id_to_fname(dblp, ndx, 0, &fname) != 0)
309                        /*
310                         * With transactional opens, we may actually have
311                         * closed this file in the transaction in which
312                         * case this will fail too.  Then it's up to the
313                         * caller to reopen the file.
314                         */
315                        return (ENOENT);
316
317                /*
318                 * Note that we're relying on fname not to change, even
319                 * though we released the mutex that protects it (fq_mutex)
320                 * inside __dbreg_id_to_fname.  This should be a safe
321                 * assumption, because the other process that has the file
322                 * open shouldn't be closing it while we're trying to abort.
323                 */
324                name = R_ADDR(&dblp->reginfo, fname->name_off);
325
326                /*
327                 * At this point, we are not holding the thread lock, so exit
328                 * directly instead of going through the exit code at the
329                 * bottom.  If the __dbreg_do_open succeeded, then we don't need
330                 * to do any of the remaining error checking at the end of this
331                 * routine.
332                 * XXX I am sending a NULL txnlist and 0 txnid which may be
333                 * completely broken ;(
334                 */
335                if ((ret = __dbreg_do_open(dbenv, txn, dblp,
336                    fname->ufid, name, fname->s_type,
337                    ndx, fname->meta_pgno, NULL, 0)) != 0)
338                        return (ret);
339
340                *dbpp = dblp->dbentry[ndx].dbp;
341                return (0);
342        }
343
344        /*
345         * Return DB_DELETED if the file has been deleted (it's not an error).
346         */
347        if (dblp->dbentry[ndx].deleted) {
348                ret = DB_DELETED;
349                goto err;
350        }
351
352        /* It's an error if we don't have a corresponding writeable DB. */
353        if ((*dbpp = dblp->dbentry[ndx].dbp) == NULL)
354                ret = ENOENT;
355
356err:    MUTEX_THREAD_UNLOCK(dbenv, dblp->mutexp);
357        return (ret);
358}
359
360/*
361 * __dbreg_id_to_fname --
362 *      Traverse the shared-memory region looking for the entry that
363 *      matches the passed dbreg id.  Returns 0 on success; -1 on error.
364 *
365 * PUBLIC: int __dbreg_id_to_fname __P((DB_LOG *, int32_t, int, FNAME **));
366 */
367int
368__dbreg_id_to_fname(dblp, lid, have_lock, fnamep)
369        DB_LOG *dblp;
370        int32_t lid;
371        int have_lock;
372        FNAME **fnamep;
373{
374        DB_ENV *dbenv;
375        FNAME *fnp;
376        LOG *lp;
377        int ret;
378
379        dbenv = dblp->dbenv;
380        lp = dblp->reginfo.primary;
381
382        ret = -1;
383
384        if (!have_lock)
385                MUTEX_LOCK(dbenv, &lp->fq_mutex);
386        for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
387            fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
388                if (fnp->id == lid) {
389                        *fnamep = fnp;
390                        ret = 0;
391                        break;
392                }
393        }
394        if (!have_lock)
395                MUTEX_UNLOCK(dbenv, &lp->fq_mutex);
396
397        return (ret);
398}
399/*
400 * __dbreg_fid_to_fname --
401 *      Traverse the shared-memory region looking for the entry that
402 *      matches the passed file unique id.  Returns 0 on success; -1 on error.
403 *
404 * PUBLIC: int __dbreg_fid_to_fname __P((DB_LOG *, u_int8_t *, int, FNAME **));
405 */
406int
407__dbreg_fid_to_fname(dblp, fid, have_lock, fnamep)
408        DB_LOG *dblp;
409        u_int8_t *fid;
410        int have_lock;
411        FNAME **fnamep;
412{
413        DB_ENV *dbenv;
414        FNAME *fnp;
415        LOG *lp;
416        int ret;
417
418        dbenv = dblp->dbenv;
419        lp = dblp->reginfo.primary;
420
421        ret = -1;
422
423        if (!have_lock)
424                MUTEX_LOCK(dbenv, &lp->fq_mutex);
425        for (fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
426            fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
427                if (memcmp(fnp->ufid, fid, DB_FILE_ID_LEN) == 0) {
428                        *fnamep = fnp;
429                        ret = 0;
430                        break;
431                }
432        }
433        if (!have_lock)
434                MUTEX_UNLOCK(dbenv, &lp->fq_mutex);
435
436        return (ret);
437}
438
439/*
440 * __dbreg_get_name
441 *
442 * Interface to get name of registered files.  This is mainly diagnostic
443 * and the name passed could be transient unless there is something
444 * ensuring that the file cannot be closed.
445 *
446 * PUBLIC: int __dbreg_get_name __P((DB_ENV *, u_int8_t *, char **));
447 */
448int
449__dbreg_get_name(dbenv, fid, namep)
450        DB_ENV *dbenv;
451        u_int8_t *fid;
452        char **namep;
453{
454        DB_LOG *dblp;
455        FNAME *fname;
456
457        dblp = dbenv->lg_handle;
458
459        if (dblp != NULL && __dbreg_fid_to_fname(dblp, fid, 0, &fname) == 0) {
460                *namep = R_ADDR(&dblp->reginfo, fname->name_off);
461                return (0);
462        }
463
464        return (-1);
465}
466
467/*
468 * __dbreg_do_open --
469 *      Open files referenced in the log.  This is the part of the open that
470 * is not protected by the thread mutex.
471 * PUBLIC: int __dbreg_do_open __P((DB_ENV *, DB_TXN *, DB_LOG *, u_int8_t *,
472 * PUBLIC:     char *, DBTYPE, int32_t, db_pgno_t, void *, u_int32_t));
473 */
474int
475__dbreg_do_open(dbenv,
476    txn, lp, uid, name, ftype, ndx, meta_pgno, info, id)
477        DB_ENV *dbenv;
478        DB_TXN *txn;
479        DB_LOG *lp;
480        u_int8_t *uid;
481        char *name;
482        DBTYPE ftype;
483        int32_t ndx;
484        db_pgno_t meta_pgno;
485        void *info;
486        u_int32_t id;
487{
488        DB *dbp;
489        int ret;
490        u_int32_t cstat;
491
492        if ((ret = db_create(&dbp, lp->dbenv, 0)) != 0)
493                return (ret);
494
495        /*
496         * We can open files under a number of different scenarios.
497         * First, we can open a file during a normal txn_abort, if that file
498         * was opened and closed during the transaction (as is the master
499         * database of a sub-database).
500         * Second, we might be aborting a transaction in XA and not have
501         * it open in the process that is actually doing the abort.
502         * Third, we might be in recovery.
503         * In case 3, there is no locking, so there is no issue.
504         * In cases 1 and 2, we are guaranteed to already hold any locks
505         * that we need, since we're still in the same transaction, so by
506         * setting DB_AM_RECOVER, we guarantee that we don't log and that
507         * we don't try to acquire locks on behalf of a different locker id.
508         */
509        F_SET(dbp, DB_AM_RECOVER);
510        if (meta_pgno != PGNO_BASE_MD) {
511                memcpy(dbp->fileid, uid, DB_FILE_ID_LEN);
512                dbp->meta_pgno = meta_pgno;
513        }
514        dbp->type = ftype;
515        if ((ret = __db_dbopen(dbp, txn, name, NULL,
516            DB_ODDFILESIZE, __db_omode("rw----"), meta_pgno)) == 0) {
517
518                /*
519                 * Verify that we are opening the same file that we were
520                 * referring to when we wrote this log record.
521                 */
522                if ((meta_pgno != PGNO_BASE_MD &&
523                    __dbreg_check_master(dbenv, uid, name) != 0) ||
524                    memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0)
525                        cstat = TXN_IGNORE;
526                else
527                        cstat = TXN_EXPECTED;
528
529                /* Assign the specific dbreg id to this dbp. */
530                if ((ret = __dbreg_assign_id(dbp, ndx)) != 0)
531                        goto err;
532
533                /*
534                 * If we successfully opened this file, then we need to
535                 * convey that information to the txnlist so that we
536                 * know how to handle the subtransaction that created
537                 * the file system object.
538                 */
539                if (id != TXN_INVALID) {
540                        if ((ret = __db_txnlist_update(dbenv,
541                            info, id, cstat, NULL)) == TXN_NOTFOUND)
542                                ret = __db_txnlist_add(dbenv,
543                                    info, id, cstat, NULL);
544                        else if (ret > 0)
545                                ret = 0;
546                }
547err:            if (cstat == TXN_IGNORE)
548                        goto not_right;
549                return (ret);
550        } else {
551                /* Record that the open failed in the txnlist. */
552                if (id != TXN_INVALID && (ret = __db_txnlist_update(dbenv,
553                    info, id, TXN_UNEXPECTED, NULL)) == TXN_NOTFOUND)
554                        ret = __db_txnlist_add(dbenv,
555                            info, id, TXN_UNEXPECTED, NULL);
556        }
557not_right:
558        (void)dbp->close(dbp, 0);
559        /* Add this file as deleted. */
560        (void)__dbreg_add_dbentry(dbenv, lp, NULL, ndx);
561        return (ENOENT);
562}
563
564static int
565__dbreg_check_master(dbenv, uid, name)
566        DB_ENV *dbenv;
567        u_int8_t *uid;
568        char *name;
569{
570        DB *dbp;
571        int ret;
572
573        ret = 0;
574        if ((ret = db_create(&dbp, dbenv, 0)) != 0)
575                return (ret);
576        dbp->type = DB_BTREE;
577        F_SET(dbp, DB_AM_RECOVER);
578        ret = __db_dbopen(dbp,
579            NULL, name, NULL, 0, __db_omode("rw----"), PGNO_BASE_MD);
580
581        if (ret == 0 && memcmp(uid, dbp->fileid, DB_FILE_ID_LEN) != 0)
582                ret = EINVAL;
583
584        (void)dbp->close(dbp, 0);
585        return (ret);
586}
587
588/*
589 * __dbreg_lazy_id --
590 *      When a replication client gets upgraded to being a replication master,
591 * it may have database handles open that have not been assigned an ID, but
592 * which have become legal to use for logging.
593 *
594 *      This function lazily allocates a new ID for such a function, in a
595 * new transaction created for the purpose.  We need to do this in a new
596 * transaction because we definitely wish to commit the dbreg_register, but
597 * at this point we have no way of knowing whether the log record that incited
598 * us to call this will be part of a committed transaction.
599 *
600 * PUBLIC: int __dbreg_lazy_id __P((DB *));
601 */
602int
603__dbreg_lazy_id(dbp)
604        DB *dbp;
605{
606        DB_ENV *dbenv;
607        DB_TXN *txn;
608        int ret;
609
610        dbenv = dbp->dbenv;
611
612        DB_ASSERT(F_ISSET(dbenv, DB_ENV_REP_MASTER));
613
614        if ((ret = dbenv->txn_begin(dbenv, NULL, &txn, 0)) != 0)
615                return (ret);
616
617        if ((ret = __dbreg_new_id(dbp, txn)) != 0) {
618                (void)txn->abort(txn);
619                return (ret);
620        }
621
622        return (txn->commit(txn, DB_TXN_NOSYNC));
623}
624
625/*
626 * __dbreg_push_id and __dbreg_pop_id --
627 *      Dbreg ids from closed files are kept on a stack in shared memory
628 * for recycling.  (We want to reuse them as much as possible because each
629 * process keeps open files in an array by ID.)  Push them to the stack and
630 * pop them from it, managing memory as appropriate.
631 *
632 * The stack is protected by the fq_mutex, and in both functions we assume
633 * that this is already locked.
634 *
635 * PUBLIC: int __dbreg_push_id __P((DB_ENV *, int32_t));
636 * PUBLIC: int __dbreg_pop_id __P((DB_ENV *, int32_t *));
637 */
638int
639__dbreg_push_id(dbenv, id)
640        DB_ENV *dbenv;
641        int32_t id;
642{
643        DB_LOG *dblp;
644        LOG *lp;
645        int32_t *stack, *newstack;
646        int ret;
647
648        dblp = dbenv->lg_handle;
649        lp = dblp->reginfo.primary;
650
651        if (lp->free_fid_stack != INVALID_ROFF)
652                stack = R_ADDR(&dblp->reginfo, lp->free_fid_stack);
653        else
654                stack = NULL;
655
656        /* Check if we have room on the stack. */
657        if (lp->free_fids_alloced <= lp->free_fids + 1) {
658                R_LOCK(dbenv, &dblp->reginfo);
659                if ((ret = __db_shalloc(dblp->reginfo.addr,
660                    (lp->free_fids_alloced + 20) * sizeof(u_int32_t), 0,
661                    &newstack)) != 0) {
662                        R_UNLOCK(dbenv, &dblp->reginfo);
663                        return (ret);
664                }
665
666                memcpy(newstack, stack,
667                    lp->free_fids_alloced * sizeof(u_int32_t));
668                lp->free_fid_stack = R_OFFSET(&dblp->reginfo, newstack);
669                lp->free_fids_alloced += 20;
670
671                if (stack != NULL)
672                        __db_shalloc_free(dblp->reginfo.addr, stack);
673
674                stack = newstack;
675                R_UNLOCK(dbenv, &dblp->reginfo);
676        }
677
678        DB_ASSERT(stack != NULL);
679        stack[lp->free_fids++] = id;
680        return (0);
681}
682
683int
684__dbreg_pop_id(dbenv, id)
685        DB_ENV *dbenv;
686        int32_t *id;
687{
688        DB_LOG *dblp;
689        LOG *lp;
690        int32_t *stack;
691
692        dblp = dbenv->lg_handle;
693        lp = dblp->reginfo.primary;
694
695        /* Do we have anything to pop? */
696        if (lp->free_fid_stack != INVALID_ROFF && lp->free_fids > 0) {
697                stack = R_ADDR(&dblp->reginfo, lp->free_fid_stack);
698                *id = stack[--lp->free_fids];
699        } else
700                *id = DB_LOGFILEID_INVALID;
701
702        return (0);
703}
704
705/*
706 * __dbreg_pluck_id --
707 *      Remove a particular dbreg id from the stack of free ids.  This is
708 * used when we open a file, as in recovery, with a specific ID that might
709 * be on the stack.
710 *
711 * Returns success whether or not the particular id was found, and like
712 * push and pop, assumes that the fq_mutex is locked.
713 *
714 * PUBLIC: int __dbreg_pluck_id __P((DB_ENV *, int32_t));
715 */
716int
717__dbreg_pluck_id(dbenv, id)
718        DB_ENV *dbenv;
719        int32_t id;
720{
721        DB_LOG *dblp;
722        LOG *lp;
723        int32_t *stack;
724        int i;
725
726        dblp = dbenv->lg_handle;
727        lp = dblp->reginfo.primary;
728
729        /* Do we have anything to look at? */
730        if (lp->free_fid_stack != INVALID_ROFF) {
731                stack = R_ADDR(&dblp->reginfo, lp->free_fid_stack);
732                for (i = 0; i < lp->free_fids; i++)
733                        if (id == stack[i]) {
734                                /*
735                                 * Found it.  Overwrite it with the top
736                                 * id (which may harmlessly be itself),
737                                 * and shorten the stack by one.
738                                 */
739                                stack[i] = stack[lp->free_fids - 1];
740                                lp->free_fids--;
741                                return (0);
742                        }
743        }
744
745        return (0);
746}
747
748#ifdef DEBUG
749/*
750 * __dbreg_print_dblist --
751 *      Display the list of files.
752 *
753 * PUBLIC: void __dbreg_print_dblist __P((DB_ENV *));
754 */
755void
756__dbreg_print_dblist(dbenv)
757        DB_ENV *dbenv;
758{
759        DB *dbp;
760        DB_LOG *dblp;
761        FNAME *fnp;
762        LOG *lp;
763        int del, first;
764        char *name;
765
766        dblp = dbenv->lg_handle;
767        lp = dblp->reginfo.primary;
768
769        MUTEX_LOCK(dbenv, &lp->fq_mutex);
770
771        for (first = 1, fnp = SH_TAILQ_FIRST(&lp->fq, __fname);
772            fnp != NULL; fnp = SH_TAILQ_NEXT(fnp, q, __fname)) {
773                if (first) {
774                        first = 0;
775                        __db_err(dbenv,
776                            "ID\t\t\tName\tType\tPgno\tTxnid\tDBP-info");
777                }
778                if (fnp->name_off == INVALID_ROFF)
779                        name = "";
780                else
781                        name = R_ADDR(&dblp->reginfo, fnp->name_off);
782
783                dbp = fnp->id >= dblp->dbentry_cnt ? NULL :
784                    dblp->dbentry[fnp->id].dbp;
785                del = fnp->id >= dblp->dbentry_cnt ? 0 :
786                    dblp->dbentry[fnp->id].deleted;
787                __db_err(dbenv, "%ld\t%s\t\t\t%s\t%lu\t%lx\t%s %d %lx %lx",
788                    (long)fnp->id, name,
789                    __db_dbtype_to_string(fnp->s_type),
790                    (u_long)fnp->meta_pgno, (u_long)fnp->create_txnid,
791                    dbp == NULL ? "No DBP" : "DBP", del, P_TO_ULONG(dbp),
792                    dbp == NULL ? 0 : dbp->flags);
793        }
794
795        MUTEX_UNLOCK(dbenv, &lp->fq_mutex);
796}
797#endif
Note: See TracBrowser for help on using the repository browser.