📄 qam.c
字号:
ret = DB_NOTFOUND; goto err; } pagep = cp->page; qp = QAM_GET_RECORD(dbp, pagep, cp->indx); if (DBC_LOGGING(dbc)) { if (((QUEUE *)dbp->q_internal)->page_ext == 0 || ((QUEUE *)dbp->q_internal)->re_len == 0) { if ((ret = __qam_del_log(dbp, dbc->txn, &LSN(pagep), 0, &LSN(pagep), pagep->pgno, cp->indx, cp->recno)) != 0) goto err; } else { data.size = ((QUEUE *)dbp->q_internal)->re_len; data.data = qp->data; if ((ret = __qam_delext_log(dbp, dbc->txn, &LSN(pagep), 0, &LSN(pagep), pagep->pgno, cp->indx, cp->recno, &data)) != 0) goto err; } } F_CLR(qp, QAM_VALID); if (cp->recno == first) { pg = ((QUEUE *)dbp->q_internal)->q_meta; if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_WRITE, 0, &metalock)) != 0) goto err; ret = __qam_consume(dbc, meta, first); if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0) ret = t_ret; }err: if ((t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0) ret = t_ret; if (cp->page != NULL && (t_ret = __qam_fput(dbp, cp->pgno, cp->page, ret == 0 ? DB_MPOOL_DIRTY : 0)) != 0 && ret == 0) ret = t_ret; cp->page = NULL; /* Doing record locking, release the page lock */ if ((t_ret = __LPUT(dbc, cp->lock)) != 0 && ret == 0) ret = t_ret; cp->lock = lock; return (ret);}#ifdef DEBUG_WOP#define QDEBUG#endif/* * __qam_c_get -- * Queue cursor->c_get function. */static int__qam_c_get(dbc, key, data, flags, pgnop) DBC *dbc; DBT *key, *data; u_int32_t flags; db_pgno_t *pgnop;{ DB *dbp; DBC *dbcdup; DBT tmp; DB_ENV *dbenv; DB_LOCK lock, pglock, metalock; DB_MPOOLFILE *mpf; PAGE *pg; QAMDATA *qp; QMETA *meta; QUEUE *t; QUEUE_CURSOR *cp; db_lockmode_t lock_mode; db_pgno_t metapno; db_recno_t first; qam_position_mode mode; int exact, inorder, is_first, locked, ret, t_ret, wait, with_delete; int put_mode, retrying; dbp = dbc->dbp; dbenv = dbp->dbenv; mpf = dbp->mpf; cp = (QUEUE_CURSOR *)dbc->internal; PANIC_CHECK(dbenv); wait = 0; with_delete = 0; retrying = 0; lock_mode = DB_LOCK_READ; meta = NULL; inorder = F_ISSET(dbp, DB_AM_INORDER); put_mode = 0; t_ret = 0; *pgnop = 0; pg = NULL; mode = QAM_READ; if (F_ISSET(dbc, DBC_RMW)) { lock_mode = DB_LOCK_WRITE; mode = QAM_WRITE; } if (flags == DB_CONSUME_WAIT) { wait = 1; flags = DB_CONSUME; } if (flags == DB_CONSUME) { with_delete = 1; flags = DB_FIRST; lock_mode = DB_LOCK_WRITE; mode = QAM_CONSUME; } DEBUG_LREAD(dbc, dbc->txn, "qam_c_get", flags == DB_SET || flags == DB_SET_RANGE ? key : NULL, NULL, flags); /* Make lint and friends happy. */ locked = 0; is_first = 0; t = (QUEUE *)dbp->q_internal; metapno = t->q_meta; /* * Get the meta page first, we don't want to write lock it while * trying to pin it. This is because someone my have it pinned * but not locked. */ if ((ret = __memp_fget(mpf, &metapno, 0, &meta)) != 0) return (ret); if ((ret = __db_lget(dbc, 0, metapno, lock_mode, 0, &metalock)) != 0) goto err; locked = 1; first = 0; /* Release any previous lock if not in a transaction. */ if ((ret = __TLPUT(dbc, cp->lock)) != 0) goto err;retry: /* Update the record number. */ switch (flags) { case DB_CURRENT: break; case DB_NEXT_DUP: ret = DB_NOTFOUND; goto err; /* NOTREACHED */ case DB_NEXT: case DB_NEXT_NODUP:get_next: if (cp->recno != RECNO_OOB) { ++cp->recno; /* Wrap around, skipping zero. */ if (cp->recno == RECNO_OOB) cp->recno++; /* * Check to see if we are out of data. */ if (cp->recno == meta->cur_recno || QAM_AFTER_CURRENT(meta, cp->recno)) { pg = NULL; if (!wait) { ret = DB_NOTFOUND; goto err; } flags = DB_FIRST; /* * If first is not set, then we skipped * a locked record, go back and find it. * If we find a locked record again * wait for it. */ if (first == 0) { retrying = 1; goto retry; } if (CDB_LOCKING(dbenv)) { /* Drop the metapage before we wait. */ if ((ret = __memp_fput(mpf, meta, 0)) != 0) goto err; meta = NULL; if ((ret = __lock_get( dbenv, dbc->locker, DB_LOCK_SWITCH, &dbc->lock_dbt, DB_LOCK_WAIT, &dbc->mylock)) != 0) goto err; if ((ret = __memp_fget(mpf, &metapno, 0, &meta)) != 0) goto err; if ((ret = __lock_get( dbenv, dbc->locker, DB_LOCK_UPGRADE, &dbc->lock_dbt, DB_LOCK_WRITE, &dbc->mylock)) != 0) goto err; goto retry; } /* * Wait for someone to update the meta page. * This will probably mean there is something * in the queue. We then go back up and * try again. */ if (locked == 0) { if ((ret = __db_lget(dbc, 0, metapno, lock_mode, 0, &metalock)) != 0) goto err; locked = 1; if (cp->recno != meta->cur_recno && cp->recno != RECNO_OOB && !QAM_AFTER_CURRENT(meta, cp->recno)) goto retry; } /* Drop the metapage before we wait. */ if ((ret = __memp_fput(mpf, meta, 0)) != 0) goto err; meta = NULL; if ((ret = __db_lget(dbc, 0, metapno, DB_LOCK_WAIT, DB_LOCK_SWITCH, &metalock)) != 0) { if (ret == DB_LOCK_DEADLOCK) ret = DB_LOCK_NOTGRANTED; goto err; } if ((ret = __memp_fget( mpf, &metapno, 0, &meta)) != 0) goto err; if ((ret = __db_lget(dbc, 0, PGNO_INVALID, DB_LOCK_WRITE, DB_LOCK_UPGRADE, &metalock)) != 0) { if (ret == DB_LOCK_DEADLOCK) ret = DB_LOCK_NOTGRANTED; goto err; } locked = 1; goto retry; } break; } /* FALLTHROUGH */ case DB_FIRST: flags = DB_NEXT; is_first = 1; /* get the first record number */ cp->recno = first = meta->first_recno; break; case DB_PREV: case DB_PREV_NODUP: if (cp->recno != RECNO_OOB) { if (cp->recno == meta->first_recno || QAM_BEFORE_FIRST(meta, cp->recno)) { ret = DB_NOTFOUND; goto err; } --cp->recno; /* Wrap around, skipping zero. */ if (cp->recno == RECNO_OOB) --cp->recno; break; } /* FALLTHROUGH */ case DB_LAST: if (meta->first_recno == meta->cur_recno) { ret = DB_NOTFOUND; goto err; } cp->recno = meta->cur_recno - 1; if (cp->recno == RECNO_OOB) cp->recno--; break; case DB_SET: case DB_SET_RANGE: case DB_GET_BOTH: case DB_GET_BOTH_RANGE: if ((ret = __qam_getno(dbp, key, &cp->recno)) != 0) goto err; if (QAM_NOT_VALID(meta, cp->recno)) { ret = DB_NOTFOUND; goto err; } break; default: ret = __db_unknown_flag(dbenv, "__qam_c_get", flags); goto err; } /* Don't hold the meta page long term. */ if (locked) { if ((ret = __LPUT(dbc, metalock)) != 0) goto err; locked = 0; } /* Lock the record. */ if ((ret = __db_lget(dbc, 0, cp->recno, lock_mode, (with_delete && !retrying) ? DB_LOCK_NOWAIT | DB_LOCK_RECORD : DB_LOCK_RECORD, &lock)) == DB_LOCK_DEADLOCK && with_delete) {#ifdef QDEBUG __db_logmsg(dbenv, dbc->txn, "Queue S", 0, "%x %d %d %d", dbc->locker, cp->recno, first, meta->first_recno);#endif first = 0; if ((ret = __db_lget(dbc, 0, metapno, lock_mode, 0, &metalock)) != 0) goto err; locked = 1; goto retry; } if (ret != 0) goto err; /* * In the DB_FIRST or DB_LAST cases we must wait and then start over * since the first/last may have moved while we slept. * We release our locks and try again. */ if (((inorder || !with_delete) && is_first) || flags == DB_LAST) {get_first: if ((ret = __db_lget(dbc, 0, metapno, lock_mode, 0, &metalock)) != 0) goto err; if (cp->recno != (is_first ? meta->first_recno : (meta->cur_recno - 1))) { if ((ret = __LPUT(dbc, lock)) != 0) goto err; if (is_first) flags = DB_FIRST; locked = 1; goto retry; } /* Don't hold the meta page long term. */ if ((ret = __LPUT(dbc, metalock)) != 0) goto err; } /* Position the cursor on the record. */ if ((ret = __qam_position(dbc, &cp->recno, mode, &exact)) != 0) { /* We cannot get the page, release the record lock. */ (void)__LPUT(dbc, lock); goto err; } pg = cp->page; pglock = cp->lock; cp->lock = lock; cp->lock_mode = lock_mode; if (!exact) {release_retry: /* Release locks and retry, if possible. */ if (pg != NULL) (void)__qam_fput(dbp, cp->pgno, pg, 0); cp->page = pg = NULL; if ((ret = __LPUT(dbc, pglock)) != 0) goto err1; switch (flags) { case DB_GET_BOTH_RANGE: flags = DB_SET_RANGE; /* FALLTHROUGH */ case DB_NEXT: case DB_NEXT_NODUP: case DB_SET_RANGE: if (!with_delete) is_first = 0; /* Peek at the meta page unlocked. */ if (QAM_BEFORE_FIRST(meta, cp->recno)) goto get_first; /* FALLTHROUGH */ case DB_PREV: case DB_PREV_NODUP: case DB_LAST: if (flags == DB_LAST) flags = DB_PREV; retrying = 0; if ((ret = __LPUT(dbc, cp->lock)) != 0) goto err1; if (flags == DB_SET_RANGE) goto get_next; else goto retry; default: /* this is for the SET and GET_BOTH cases */ ret = DB_KEYEMPTY; goto err1; } } qp = QAM_GET_RECORD(dbp, pg, cp->indx); /* Return the data item. */ if (flags == DB_GET_BOTH || flags == DB_GET_BOTH_RANGE) { /* * Need to compare */ tmp.data = qp->data; tmp.size = t->re_len; if ((ret = __bam_defcmp(dbp, data, &tmp)) != 0) { if (flags == DB_GET_BOTH_RANGE) goto release_retry; ret = DB_NOTFOUND; goto err1; } } /* Return the key if the user didn't give us one. */ if (key != NULL) { if (flags != DB_GET_BOTH && flags != DB_SET && (ret = __db_retcopy(dbp->dbenv, key, &cp->recno, sizeof(cp->recno), &dbc->rkey->data, &dbc->rkey->ulen)) != 0) goto err1; F_SET(key, DB_DBT_ISSET); } if (data != NULL) { if (!F_ISSET(dbc, DBC_MULTIPLE|DBC_MULTIPLE_KEY) && (ret = __db_retcopy(dbp->dbenv, data, qp->data, t->re_len, &dbc->rdata->data, &dbc->rdata->ulen)) != 0) goto err1; F_SET(data, DB_DBT_ISSET); } /* Finally, if we are doing DB_CONSUME mark the record. */ if (with_delete) { /* * Assert that we're not a secondary index. Doing a DB_CONSUME * on a secondary makes very little sense, since one can't * DB_APPEND there; attempting one should be forbidden by * the interface. */ DB_ASSERT(!F_ISSET(dbp, DB_AM_SECONDARY)); /* * Check and see if we *have* any secondary indices. * If we do, we're a primary, so call __db_c_del_primary * to delete the references to the item we're about to * delete. * * Note that we work on a duplicated cursor, since the * __db_ret work has already been done, so it's not safe * to perform any additional ops on this cursor. */ if (LIST_FIRST(&dbp->s_secondaries) != NULL) { if ((ret = __db_c_idup(dbc, &dbcdup, DB_POSITION)) != 0) goto err1; if ((ret = __db_c_del_primary(dbcdup)) != 0) { /* * The __db_c_del_primary return is more * interesting. */ (void)__db_c_close(dbcdup); goto err1; } if ((ret = __db_c_close(dbcdup)) != 0) goto err1; } if (DBC_LOGGING(dbc)) { if (t->page_ext == 0 || t->re_len == 0) { if ((ret = __qam_del_log(dbp, dbc->txn, &LSN(pg), 0, &LSN(pg), pg->pgno, cp->indx, cp->recno)) != 0) goto err1; } else { tmp.data = qp->data; tmp.size = t->re_len; if ((ret = __qam_delext_log(dbp, dbc->txn, &LSN(pg), 0, &LSN(pg), pg->pgno, cp->indx, cp->recno, &tmp)) != 0) goto err1; } } F_CLR(qp, QAM_VALID); put_mode = DB_MPOOL_DIRTY; if ((ret = __LPUT(dbc, pglock)) != 0) goto err1; /* * Now we need to update the metapage * first pointer. If we have deleted * the record that is pointed to by * first_recno then we move it as far * forward as we can without blocking. * The metapage lock must be held for * the whole scan otherwise someone could * do a random insert behind where we are * looking. */ if (locked == 0 && (ret = __db_lget( dbc, 0, metapno, lock_mode, 0, &metalock)) != 0) goto err1; locked = 1;#ifdef QDEBUG __db_logmsg(dbenv, dbc->txn, "Queue D", 0, "%x %d %d %d", dbc->locker, cp->recno, first, meta->first_recno);#endif /* * See if we deleted the "first" record. If * first is zero then we skipped something, * see if first_recno has been move passed * that to the record that we deleted. */ if (first == 0) first = cp->recno; if (first != meta->first_recno) goto done; if ((ret = __qam_consume(dbc, meta, first)) != 0) goto err1; }done:err1: if (cp->page != NULL) { if ((t_ret = __qam_fput( dbp, cp->pgno, cp->page, put_mode)) != 0 && ret == 0) ret = t_ret; /* Doing record locking, release the page lock */ if ((t_ret = __LPUT(dbc, pglock)) != 0 && ret == 0) ret = t_ret; cp->page = NULL; }err: if (meta) { /* Release the meta page. */ if ((t_ret = __memp_fput(mpf, meta, 0)) != 0 && ret == 0) ret = t_ret; /* Don't hold the meta page long term. */ if (locked) if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0) ret = t_ret; } DB_ASSERT(!LOCK_ISSET(metalock));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -