📄 db_dispatch.c
字号:
db_pgno_t pgno; db_lockmode_t mode; DB_TXN *ptxn, *txn;{ DBT lock_dbt; DB_LOCK lock; DB_LOCK_ILOCK lock_obj; DB_LOCKREQ req; int ret; lock_obj.pgno = pgno; memcpy(lock_obj.fileid, fileid, DB_FILE_ID_LEN); lock_obj.type = DB_PAGE_LOCK; memset(&lock_dbt, 0, sizeof(lock_dbt)); lock_dbt.data = &lock_obj; lock_dbt.size = sizeof(lock_obj); if ((ret = dbenv->lock_get(dbenv, txn->txnid, 0, &lock_dbt, mode, &lock)) == 0) { memset(&req, 0, sizeof(req)); req.lock = lock; req.op = DB_LOCK_TRADE; ret = dbenv->lock_vec(dbenv, ptxn->txnid, 0, &req, 1, NULL); } return (ret);}/* * __db_limbo_move * Move just the metapage lock to the parent. */static int__db_limbo_move(dbenv, ptxn, txn, elp) DB_ENV *dbenv; DB_TXN *ptxn, *txn; DB_TXNLIST *elp;{ int ret; for (; elp != NULL; elp = LIST_NEXT(elp, links)) { if (elp->type != TXNLIST_PGNO || elp->u.p.locked == 1) continue; if ((ret = __db_lock_move(dbenv, elp->u.p.uid, PGNO_BASE_MD, DB_LOCK_WRITE, ptxn, txn)) != 0) return (ret); elp->u.p.locked = 1; } return (0);}/* * __db_limbo_bucket * Perform limbo processing for a single hash bucket in the txnlist. * txn is the transaction aborting in the case of an abort and ctxn is the * compensating transaction. */#define T_RESTORED(txn) ((txn) != NULL && F_ISSET(txn, TXN_RESTORED))static int__db_limbo_bucket(dbenv, txn, elp) DB_ENV *dbenv; DB_TXN *txn; DB_TXNLIST *elp;{ DB *dbp; DB_MPOOLFILE *mpf; DBMETA *meta; DB_TXN *ctxn, *t; db_pgno_t last_pgno, pgno; int dbp_created, in_retry, ret, t_ret; ctxn = NULL; in_retry = 0; meta = NULL; mpf = NULL; ret = 0; for (; elp != NULL; elp = LIST_NEXT(elp, links)) { if (elp->type != TXNLIST_PGNO) continue;retry: dbp_created = 0; /* * Pick the transaction in which to potentially * log compensations. */ if (!in_retry && !IS_RECOVERING(dbenv) && !T_RESTORED(txn) && (ret = __txn_compensate_begin(dbenv, &ctxn)) != 0) return (ret); /* * Either use the compensating transaction or * the one passed in, which will be null if recovering. */ t = ctxn == NULL ? txn : ctxn; /* First try to get a dbp by fileid. */ ret = __dbreg_id_to_db(dbenv, t, &dbp, elp->u.p.fileid, 0); /* * File is being destroyed. No need to worry about * dealing with recovery of allocations. */ if (ret == DB_DELETED || (ret == 0 && F_ISSET(dbp, DB_AM_DISCARD))) goto next; if (ret != 0) { if ((ret = db_create(&dbp, dbenv, 0)) != 0) goto err; /* * This tells the system not to lock, which is always * OK, whether this is an abort or recovery. */ F_SET(dbp, DB_AM_COMPENSATE); dbp_created = 1; /* It is ok if the file is nolonger there. */ dbp->type = DB_UNKNOWN; ret = __db_dbopen(dbp, t, elp->u.p.fname, NULL, DB_ODDFILESIZE, __db_omode("rw----"), PGNO_BASE_MD); if (ret == ENOENT) goto next; } /* * Verify that we are opening the same file that we were * referring to when we wrote this log record. */ if (memcmp(elp->u.p.uid, dbp->fileid, DB_FILE_ID_LEN) != 0) goto next; mpf = dbp->mpf; last_pgno = PGNO_INVALID; if (ctxn == NULL) { pgno = PGNO_BASE_MD; if ((ret = mpf->get(mpf, &pgno, 0, (PAGE **)&meta)) != 0) goto err; last_pgno = meta->free; } ret = __db_limbo_fix(dbp, ctxn, elp, &last_pgno, meta); /* * If we were doing compensating transactions, then we are * going to hope this error was due to running out of space. * We'll change modes (into the sync the file mode) and keep * trying. If we weren't doing compensating transactions, * then this is a real error and we're sunk. */ if (ret != 0) { if (ret == DB_RUNRECOVERY || ctxn == NULL) goto err; in_retry = 1; goto retry; } if (ctxn != NULL) { ret = ctxn->commit(ctxn, DB_TXN_NOSYNC); ctxn = NULL; if (ret != 0) goto retry; goto next; } /* * This is where we handle the case where we're explicitly * putting together a free list. We need to decide whether * we have to write the meta-data page, and if we do, then * we need to sync it as well. */ if (last_pgno == meta->free) { /* No change to page; just put the page back. */ if ((ret = mpf->put(mpf, meta, 0)) != 0) goto err; meta = NULL; } else { /* * These changes are unlogged so we cannot have the * metapage pointing at pages that are not on disk. * Therefore, we flush the new free list, then update * the metapage. We have to put the meta-data page * first so that it isn't pinned when we try to sync. */ if (!IS_RECOVERING(dbenv) && !T_RESTORED(txn)) __db_err(dbenv, "Flushing free list to disk"); if ((ret = mpf->put(mpf, meta, 0)) != 0) goto err; meta = NULL; dbp->sync(dbp, 0); pgno = PGNO_BASE_MD; if ((ret = mpf->get(mpf, &pgno, 0, (PAGE **)&meta)) != 0) goto err; meta->free = last_pgno; if ((ret = mpf->put(mpf, meta, DB_MPOOL_DIRTY)) != 0) goto err; meta = NULL; }next: /* * If we get here, either we have processed the list * or the db file has been deleted or could no be opened. */ if (ctxn != NULL && (t_ret = ctxn->abort(ctxn)) != 0 && ret == 0) ret = t_ret; if (dbp_created && (t_ret = __db_close_i(dbp, txn, 0)) != 0 && ret == 0) ret = t_ret; dbp = NULL; __os_free(dbenv, elp->u.p.fname); __os_free(dbenv, elp->u.p.pgno_array); if (ret == ENOENT) ret = 0; else if (ret != 0) goto err; }err: if (meta != NULL) (void)mpf->put(mpf, meta, 0); return (ret);}/* * __db_limbo_fix -- * Process a single limbo entry which describes all the page allocations * for a single file. */static int__db_limbo_fix(dbp, ctxn, elp, lastp, meta) DB *dbp; DB_TXN *ctxn; DB_TXNLIST *elp; db_pgno_t *lastp; DBMETA *meta;{ DBC *dbc; DB_MPOOLFILE *mpf; PAGE *freep, *pagep; db_pgno_t next, pgno; int i, put_page, ret, t_ret; /* * Loop through the entries for this txnlist element and * either link them into the free list or write a compensating * record for each. */ put_page = 0; ret = 0; mpf = dbp->mpf; dbc = NULL; for (i = 0; i < elp->u.p.nentries; i++) { pgno = elp->u.p.pgno_array[i]; if ((ret = mpf->get(mpf, &pgno, DB_MPOOL_CREATE, &pagep)) != 0) goto err; put_page = 1; if (IS_ZERO_LSN(LSN(pagep))) { if (ctxn == NULL) { /* * If this is a fatal recovery which * spans a previous crash this page may * be on the free list already. */ for (next = *lastp; next != 0; ) { if (next == pgno) break; if ((ret = mpf->get(mpf, &next, 0, &freep)) != 0) goto err; next = NEXT_PGNO(freep); if ((ret = mpf->put(mpf, freep, 0)) != 0) goto err; } if (next != pgno) { P_INIT(pagep, dbp->pgsize, pgno, PGNO_INVALID, *lastp, 0, P_INVALID); LSN(pagep) = LSN(meta); *lastp = pgno; } } else { P_INIT(pagep, dbp->pgsize, pgno, PGNO_INVALID, *lastp, 0, P_INVALID); if (dbc == NULL && (ret = dbp->cursor(dbp, ctxn, &dbc, 0)) != 0) goto err; /* * If the dbp is compensating (because we * opened it), the dbc will automatically be * marked compensating, but in case we didn't * do the open, we have to mark it explicitly. */ F_SET(dbc, DBC_COMPENSATE); ret = __db_free(dbc, pagep); put_page = 0; /* * On any error, we hope that the error was * caused due to running out of space, and we * switch modes, doing the processing where we * sync out files instead of doing compensating * transactions. If this was a real error and * not out of space, we assume that some other * call will fail real soon. */ if (ret != 0) { /* Assume that this is out of space. */ (void)dbc->c_close(dbc); dbc = NULL; goto err; } } } if (put_page == 1) { ret = mpf->put(mpf, pagep, DB_MPOOL_DIRTY); put_page = 0; } if (ret != 0) goto err; }err: if (put_page && (t_ret = mpf->put(mpf, pagep, DB_MPOOL_DIRTY)) != 0 && ret == 0) ret = t_ret; if (dbc != NULL && (t_ret = dbc->c_close(dbc)) != 0 && ret == 0) ret = t_ret; return (ret);}#define DB_TXNLIST_MAX_PGNO 8 /* A nice even number. *//* * __db_txnlist_pgnoadd -- * Find the txnlist entry for a file and add this pgno, or add the list * entry for the file and then add the pgno. */static int__db_txnlist_pgnoadd(dbenv, hp, fileid, uid, fname, pgno) DB_ENV *dbenv; DB_TXNHEAD *hp; int32_t fileid; u_int8_t uid[DB_FILE_ID_LEN]; char *fname; db_pgno_t pgno;{ DB_TXNLIST *elp; u_int32_t hash; int len, ret; elp = NULL; if (__db_txnlist_find_internal(dbenv, hp, TXNLIST_PGNO, 0, uid, &elp, 0) != 0) { if ((ret = __os_malloc(dbenv, sizeof(DB_TXNLIST), &elp)) != 0) goto err; memcpy(&hash, uid, sizeof(hash)); LIST_INSERT_HEAD( &hp->head[DB_TXNLIST_MASK(hp, hash)], elp, links); elp->u.p.fileid = fileid; memcpy(elp->u.p.uid, uid, DB_FILE_ID_LEN); len = (int)strlen(fname) + 1; if ((ret = __os_malloc(dbenv, len, &elp->u.p.fname)) != 0) goto err; memcpy(elp->u.p.fname, fname, len); elp->u.p.maxentry = 0; elp->u.p.locked = 0; elp->type = TXNLIST_PGNO; if ((ret = __os_malloc(dbenv, 8 * sizeof(db_pgno_t), &elp->u.p.pgno_array)) != 0) goto err; elp->u.p.maxentry = DB_TXNLIST_MAX_PGNO; elp->u.p.nentries = 0; } else if (elp->u.p.nentries == elp->u.p.maxentry) { elp->u.p.maxentry <<= 1; if ((ret = __os_realloc(dbenv, elp->u.p.maxentry * sizeof(db_pgno_t), &elp->u.p.pgno_array)) != 0) goto err; } elp->u.p.pgno_array[elp->u.p.nentries++] = pgno; return (0);err: __db_txnlist_end(dbenv, hp); return (ret);}/* * __db_default_getpgnos -- * Fill in default getpgnos information for an application-specific * log record. */static int__db_default_getpgnos(dbenv, lsnp, summary) DB_ENV *dbenv; DB_LSN *lsnp; void *summary;{ TXN_RECS *t; int ret; t = (TXN_RECS *)summary; if ((ret = __rep_check_alloc(dbenv, t, 1)) != 0) return (ret); t->array[t->npages].flags = LSN_PAGE_NOLOCK; t->array[t->npages].lsn = *lsnp; t->array[t->npages].fid = DB_LOGFILEID_INVALID; memset(&t->array[t->npages].pgdesc, 0, sizeof(t->array[t->npages].pgdesc)); t->npages++; return (0);}#ifdef DEBUG/* * __db_txnlist_print -- * Print out the transaction list. * * PUBLIC: void __db_txnlist_print __P((void *)); */void__db_txnlist_print(listp) void *listp;{ DB_TXNHEAD *hp; DB_TXNLIST *p; int i; char *stats[] = { "ok", "commit", "prepare", "abort", "notfound", "ignore", "expected", "unexpected" }; hp = (DB_TXNHEAD *)listp; printf("Maxid: %lu Generation: %lu\n", (u_long)hp->maxid, (u_long)hp->generation); for (i = 0; i < hp->nslots; i++) for (p = LIST_FIRST(&hp->head[i]); p != NULL; p = LIST_NEXT(p, links)) { switch (p->type) { case TXNLIST_TXNID: printf("TXNID: %lx(%lu): %s\n", (u_long)p->u.t.txnid, (u_long)p->u.t.generation, stats[p->u.t.status]); break; default: printf("Unrecognized type: %d\n", p->type); break; } }}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -