qam.c
上传用户:tsgydb
上传日期:2007-04-14
资源大小:10674k
文件大小:31k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /*-
  2.  * See the file LICENSE for redistribution information.
  3.  *
  4.  * Copyright (c) 1999, 2000
  5.  * Sleepycat Software.  All rights reserved.
  6.  */
  7. #include "db_config.h"
  8. #ifndef lint
  9. static const char revid[] = "$Id: qam.c,v 11.72 2001/01/16 20:10:55 ubell Exp $";
  10. #endif /* not lint */
  11. #ifndef NO_SYSTEM_INCLUDES
  12. #include <sys/types.h>
  13. #include <string.h>
  14. #endif
  15. #include "db_int.h"
  16. #include "db_page.h"
  17. #include "db_shash.h"
  18. #include "db_am.h"
  19. #include "mp.h"
  20. #include "lock.h"
  21. #include "log.h"
  22. #include "btree.h"
  23. #include "qam.h"
  24. static int __qam_c_close __P((DBC *, db_pgno_t, int *));
  25. static int __qam_c_del __P((DBC *));
  26. static int __qam_c_destroy __P((DBC *));
  27. static int __qam_c_get __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *));
  28. static int __qam_c_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *));
  29. static int __qam_getno __P((DB *, const DBT *, db_recno_t *));
  30. /*
  31.  * __qam_position --
  32.  * Position a queued access method cursor at a record.  This returns
  33.  * the page locked.  *exactp will be set if the record is valid.
  34.  * PUBLIC: int __qam_position
  35.  * PUBLIC:       __P((DBC *, db_recno_t *, qam_position_mode, int *));
  36.  */
  37. int
  38. __qam_position(dbc, recnop, mode, exactp)
  39. DBC *dbc; /* open cursor */
  40. db_recno_t *recnop; /* pointer to recno to find */
  41. qam_position_mode mode;/* locking: read or write */
  42. int *exactp; /* indicate if it was found */
  43. {
  44. QUEUE_CURSOR *cp;
  45. DB *dbp;
  46. QAMDATA  *qp;
  47. db_pgno_t pg;
  48. int ret;
  49. dbp = dbc->dbp;
  50. cp = (QUEUE_CURSOR *)dbc->internal;
  51. /* Fetch the page for this recno. */
  52. pg = QAM_RECNO_PAGE(dbp, *recnop);
  53. if ((ret = __db_lget(dbc, 0, pg, mode == QAM_READ ?
  54.      DB_LOCK_READ : DB_LOCK_WRITE, 0, &cp->lock)) != 0)
  55. return (ret);
  56. cp->page = NULL;
  57. *exactp = 0;
  58. if ((ret = __qam_fget(dbp, &pg,
  59.     mode == QAM_WRITE ? DB_MPOOL_CREATE : 0,
  60.     &cp->page)) != 0) {
  61. /* We did not fetch it, we can release the lock. */
  62. (void)__LPUT(dbc, cp->lock);
  63. cp->lock.off = LOCK_INVALID;
  64. if (mode != QAM_WRITE && (ret == EINVAL || ret == ENOENT))
  65. return (0);
  66. return (ret);
  67. }
  68. cp->pgno = pg;
  69. cp->indx = QAM_RECNO_INDEX(dbp, pg, *recnop);
  70. if (PGNO(cp->page) == 0) {
  71. if (F_ISSET(dbp, DB_AM_RDONLY)) {
  72. *exactp = 0;
  73. return (0);
  74. }
  75. PGNO(cp->page) = pg;
  76. TYPE(cp->page) = P_QAMDATA;
  77. }
  78. qp = QAM_GET_RECORD(dbp, cp->page, cp->indx);
  79. *exactp = F_ISSET(qp, QAM_VALID);
  80. return (ret);
  81. }
  82. /*
  83.  * __qam_pitem --
  84.  * Put an item on a queue page.  Copy the data to the page and set the
  85.  * VALID and SET bits.  If logging and the record was previously set,
  86.  * log that data, otherwise just log the new data.
  87.  *
  88.  *   pagep must be write locked
  89.  *
  90.  * PUBLIC: int __qam_pitem
  91.  * PUBLIC:     __P((DBC *,  QPAGE *, u_int32_t, db_recno_t, DBT *));
  92.  */
  93. int
  94. __qam_pitem(dbc, pagep, indx, recno, data)
  95. DBC *dbc;
  96. QPAGE *pagep;
  97. u_int32_t indx;
  98. db_recno_t recno;
  99. DBT *data;
  100. {
  101. DB *dbp;
  102. DBT olddata, pdata, *datap;
  103. QAMDATA *qp;
  104. QUEUE *t;
  105. u_int32_t size;
  106. u_int8_t *dest, *p;
  107. int alloced, ret;
  108. alloced = ret = 0;
  109. dbp = dbc->dbp;
  110. t = (QUEUE *)dbp->q_internal;
  111. if (data->size > t->re_len)
  112. goto len_err;
  113. qp = QAM_GET_RECORD(dbp, pagep, indx);
  114. p = qp->data;
  115. size = data->size;
  116. datap = data;
  117. if (F_ISSET(data, DB_DBT_PARTIAL)) {
  118. if (data->doff + data->dlen > t->re_len) {
  119. alloced = data->dlen;
  120. goto len_err;
  121. }
  122. if (data->size != data->dlen) {
  123. len_err: __db_err(dbp->dbenv,
  124.     "Length improper for fixed length record %lu",
  125.     (u_long)(alloced ? alloced : data->size));
  126. return (EINVAL);
  127. }
  128. if (data->size == t->re_len)
  129. goto no_partial;
  130. /*
  131.  * If we are logging, then we have to build the record
  132.  * first, otherwise, we can simply drop the change
  133.  * directly on the page.  After this clause, make
  134.  * sure that datap and p are set up correctly so that
  135.  * copying datap into p does the right thing.
  136.  *
  137.  * Note, I am changing this so that if the existing
  138.  * record is not valid, we create a complete record
  139.  * to log so that both this and the recovery code is simpler.
  140.  */
  141. if (DB_LOGGING(dbc) || !F_ISSET(qp, QAM_VALID)) {
  142. datap = &pdata;
  143. memset(datap, 0, sizeof(*datap));
  144. if ((ret = __os_malloc(dbp->dbenv,
  145.     t->re_len, NULL, &datap->data)) != 0)
  146. return (ret);
  147. alloced = 1;
  148. datap->size = t->re_len;
  149. /*
  150.  * Construct the record if it's valid, otherwise set it
  151.  * all to the pad character.
  152.  */
  153. dest = datap->data;
  154. if (F_ISSET(qp, QAM_VALID))
  155. memcpy(dest, p, t->re_len);
  156. else
  157. memset(dest, t->re_pad, t->re_len);
  158. dest += data->doff;
  159. memcpy(dest, data->data, data->size);
  160. } else {
  161. datap = data;
  162. p += data->doff;
  163. }
  164. }
  165. no_partial:
  166. if (DB_LOGGING(dbc)) {
  167. olddata.size = 0;
  168. if (F_ISSET(qp, QAM_SET)) {
  169. olddata.data = qp->data;
  170. olddata.size = t->re_len;
  171. }
  172. if ((ret = __qam_add_log(dbp->dbenv, dbc->txn, &LSN(pagep),
  173.     0, dbp->log_fileid, &LSN(pagep), pagep->pgno,
  174.     indx, recno, datap, qp->flags,
  175.     olddata.size == 0 ? NULL : &olddata)) != 0)
  176. goto err;
  177. }
  178. F_SET(qp, QAM_VALID | QAM_SET);
  179. memcpy(p, datap->data, datap->size);
  180. if (!F_ISSET(data, DB_DBT_PARTIAL))
  181. memset(p + datap->size,  t->re_pad, t->re_len - datap->size);
  182. err: if (alloced)
  183. __os_free(datap->data, t->re_len);
  184. return (ret);
  185. }
  186. /*
  187.  * __qam_c_put
  188.  * Cursor put for queued access method.
  189.  * BEFORE and AFTER cannot be specified.
  190.  */
  191. static int
  192. __qam_c_put(dbc, key, data, flags, pgnop)
  193. DBC *dbc;
  194. DBT *key, *data;
  195. u_int32_t flags;
  196. db_pgno_t *pgnop;
  197. {
  198. QUEUE_CURSOR *cp;
  199. DB *dbp;
  200. DB_LOCK lock;
  201. QMETA *meta;
  202. db_pgno_t pg;
  203. db_recno_t new_cur, new_first;
  204. u_int32_t opcode;
  205. int exact, ret, t_ret;
  206. COMPQUIET(key, NULL);
  207. dbp = dbc->dbp;
  208. if (pgnop != NULL)
  209. *pgnop = PGNO_INVALID;
  210. cp = (QUEUE_CURSOR *)dbc->internal;
  211. /* Write lock the record. */
  212. if ((ret = __db_lget(dbc,
  213.     0, cp->recno, DB_LOCK_WRITE, DB_LOCK_RECORD, &lock)) != 0)
  214. return (ret);
  215. if ((ret = __qam_position(dbc,
  216.     &cp->recno, QAM_WRITE, &exact)) != 0) {
  217. /* We could not get the page, we can release the record lock. */
  218. __LPUT(dbc, lock);
  219. return (ret);
  220. }
  221. if (exact && flags == DB_NOOVERWRITE) {
  222. ret = __TLPUT(dbc, lock);
  223. /* Doing record locking, release the page lock */
  224. if ((t_ret = __LPUT(dbc, cp->lock)) == 0)
  225. cp->lock.off = LOCK_INVALID;
  226. else
  227. if (ret == 0)
  228. ret = t_ret;
  229. if ((t_ret =
  230.      __qam_fput(dbp, cp->pgno, cp->page, 0)) != 0 && ret == 0)
  231. ret = t_ret;
  232. cp->page = NULL;
  233. return (ret == 0 ? DB_KEYEXIST : ret);
  234. }
  235. /* Put the item on the page. */
  236. ret = __qam_pitem(dbc, (QPAGE *)cp->page, cp->indx, cp->recno, data);
  237. /* Doing record locking, release the page lock */
  238. if ((t_ret = __LPUT(dbc, cp->lock)) != 0 && ret == 0)
  239. ret = t_ret;
  240. if ((t_ret =
  241.     __qam_fput(dbp, cp->pgno, cp->page, DB_MPOOL_DIRTY)) && ret == 0)
  242. ret = t_ret;
  243. cp->page = NULL;
  244. cp->lock = lock;
  245. cp->lock_mode = DB_LOCK_WRITE;
  246. if (ret != 0)
  247. return (ret);
  248. /* We may need to reset the head or tail of the queue. */
  249. pg = ((QUEUE *)dbp->q_internal)->q_meta;
  250. if ((ret = __db_lget(dbc, 0, pg,  DB_LOCK_WRITE, 0, &lock)) != 0)
  251. return (ret);
  252. if ((ret = memp_fget(dbp->mpf, &pg, 0, &meta)) != 0) {
  253. /* We did not fetch it, we can release the lock. */
  254. (void)__LPUT(dbc, lock);
  255. return (ret);
  256. }
  257. opcode = 0;
  258. new_cur = new_first = 0;
  259. /*
  260.  * If the put address is outside the queue, adjust the head and
  261.  * tail of the queue.  If the order is inverted we move
  262.  * the one which is closer.  The first case is when the
  263.  * queue is empty, move first and current to where the new
  264.  * insert is.
  265.  */
  266. if (meta->first_recno == meta->cur_recno) {
  267. new_first = cp->recno;
  268. new_cur = cp->recno + 1;
  269. if (new_cur == RECNO_OOB)
  270. new_cur++;
  271. opcode |= QAM_SETFIRST;
  272. opcode |= QAM_SETCUR;
  273. } else {
  274. if (QAM_BEFORE_FIRST(meta, cp->recno) &&
  275.     (meta->first_recno <= meta->cur_recno ||
  276.     meta->first_recno - cp->recno < cp->recno - meta->cur_recno)) {
  277. new_first = cp->recno;
  278. opcode |= QAM_SETFIRST;
  279. }
  280. if (meta->cur_recno == cp->recno ||
  281.     (QAM_AFTER_CURRENT(meta, cp->recno) &&
  282.     (meta->first_recno <= meta->cur_recno ||
  283.     cp->recno - meta->cur_recno <= meta->first_recno - cp->recno))) {
  284. new_cur = cp->recno + 1;
  285. if (new_cur == RECNO_OOB)
  286. new_cur++;
  287. opcode |= QAM_SETCUR;
  288. }
  289. }
  290. if (opcode != 0 && DB_LOGGING(dbc)) {
  291. ret = __qam_mvptr_log(dbp->dbenv, dbc->txn, &meta->dbmeta.lsn,
  292.     0, opcode, dbp->log_fileid, meta->first_recno, new_first,
  293.     meta->cur_recno, new_cur, &meta->dbmeta.lsn);
  294. }
  295. if (opcode & QAM_SETCUR)
  296. meta->cur_recno = new_cur;
  297. if (opcode & QAM_SETFIRST)
  298. meta->first_recno = new_first;
  299. if ((t_ret =
  300.     memp_fput(dbp->mpf, meta, opcode != 0 ? DB_MPOOL_DIRTY : 0)) != 0 &&
  301.     ret == 0)
  302. ret = t_ret;
  303. /* Don't hold the meta page long term. */
  304. if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
  305. ret = t_ret;
  306. return (ret);
  307. }
  308. /*
  309.  * __qam_put --
  310.  * Add a record to the queue.
  311.  * If we are doing anything but appending, just call qam_c_put to do the
  312.  * work.  Otherwise we fast path things here.
  313.  *
  314.  * PUBLIC: int __qam_put __P((DB *, DB_TXN *, DBT *, DBT *, u_int32_t));
  315.  */
  316. int
  317. __qam_put(dbp, txn, key, data, flags)
  318. DB *dbp;
  319. DB_TXN *txn;
  320. DBT *key, *data;
  321. u_int32_t flags;
  322. {
  323. QUEUE_CURSOR *cp;
  324. DBC *dbc;
  325. DB_LOCK lock;
  326. QMETA *meta;
  327. QPAGE *page;
  328. QUEUE *qp;
  329. db_pgno_t pg;
  330. db_recno_t recno;
  331. int ret, t_ret;
  332. PANIC_CHECK(dbp->dbenv);
  333. DB_CHECK_TXN(dbp, txn);
  334. /* Allocate a cursor. */
  335. if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
  336. return (ret);
  337. DEBUG_LWRITE(dbc, dbc->txn, "qam_put", key, data, flags);
  338. cp = (QUEUE_CURSOR *)dbc->internal;
  339. /* Check for invalid flags. */
  340. if ((ret = __db_putchk(dbp,
  341.     key, data, flags, F_ISSET(dbp, DB_AM_RDONLY), 0)) != 0)
  342. goto done;
  343. /* If not appending, then just call the cursor routine */
  344. if (flags != DB_APPEND) {
  345. if ((ret = __qam_getno(dbp, key, &cp->recno)) != 0)
  346. goto done;
  347. ret = __qam_c_put(dbc, NULL, data, flags, NULL);
  348. goto done;
  349. }
  350. /* Write lock the meta page. */
  351. pg = ((QUEUE *)dbp->q_internal)->q_meta;
  352. if ((ret = __db_lget(dbc, 0, pg,  DB_LOCK_WRITE, 0, &lock)) != 0)
  353. goto done;
  354. if ((ret = memp_fget(dbp->mpf, &pg, 0, &meta)) != 0) {
  355. /* We did not fetch it, we can release the lock. */
  356. (void)__LPUT(dbc, lock);
  357. goto done;
  358. }
  359. /* Record that we are going to allocate a record. */
  360. if (DB_LOGGING(dbc)) {
  361. __qam_inc_log(dbp->dbenv,
  362.     dbc->txn, &meta->dbmeta.lsn,
  363.     0, dbp->log_fileid, &meta->dbmeta.lsn);
  364. }
  365. /* Get the next record number. */
  366. recno = meta->cur_recno;
  367. meta->cur_recno++;
  368. if (meta->cur_recno == RECNO_OOB)
  369. meta->cur_recno++;
  370. if (meta->cur_recno == meta->first_recno) {
  371. meta->cur_recno--;
  372. if (meta->cur_recno == RECNO_OOB)
  373. meta->cur_recno--;
  374. (void)__LPUT(dbc, lock);
  375. ret = EFBIG;
  376. goto err;
  377. }
  378. if (QAM_BEFORE_FIRST(meta, recno))
  379. meta->first_recno = recno;
  380. /* Lock the record and release meta page lock. */
  381. if ((ret = __db_lget(dbc,
  382.     1, recno, DB_LOCK_WRITE, DB_LOCK_RECORD, &lock)) != 0)
  383. goto err;
  384. /*
  385.  * The application may modify the data based on the selected record
  386.  * number.
  387.  */
  388. if (flags == DB_APPEND && dbc->dbp->db_append_recno != NULL &&
  389.     (ret = dbc->dbp->db_append_recno(dbc->dbp, data, recno)) != 0) {
  390. (void)__LPUT(dbc, lock);
  391. goto err;
  392. }
  393. cp->lock = lock;
  394. cp->lock_mode = DB_LOCK_WRITE;
  395. pg = QAM_RECNO_PAGE(dbp, recno);
  396. /* Fetch and write lock the data page. */
  397. if ((ret = __db_lget(dbc, 0, pg,  DB_LOCK_WRITE, 0, &lock)) != 0)
  398. goto err;
  399. if ((ret = __qam_fget(dbp, &pg, DB_MPOOL_CREATE, &page)) != 0) {
  400. /* We did not fetch it, we can release the lock. */
  401. (void)__LPUT(dbc, lock);
  402. goto err;
  403. }
  404. /* See if this is a new page. */
  405. if (page->pgno == 0) {
  406. page->pgno = pg;
  407. page->type = P_QAMDATA;
  408. }
  409. /* Put the item on the page and log it. */
  410. ret = __qam_pitem(dbc, page,
  411.     QAM_RECNO_INDEX(dbp, pg, recno), recno, data);
  412. /* Doing record locking, release the page lock */
  413. if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
  414. ret = t_ret;
  415. if ((t_ret
  416.     = __qam_fput(dbp, pg, page, DB_MPOOL_DIRTY)) != 0 && ret == 0)
  417. ret = t_ret;
  418. /* Return the record number to the user. */
  419. if (ret == 0)
  420. ret = __db_retcopy(dbp, key,
  421.     &recno, sizeof(recno), &dbc->rkey.data, &dbc->rkey.ulen);
  422. /* See if we are leaving the extent. */
  423. qp = (QUEUE *) dbp->q_internal;
  424. if (qp->page_ext != 0
  425.     && (recno % (qp->page_ext * qp->rec_page) == 0
  426.     || recno == UINT32_T_MAX)) {
  427. if ((ret =
  428.     __db_lget(dbc, 0, pg,  DB_LOCK_WRITE, 0, &lock)) != 0)
  429. goto err;
  430. if (!QAM_AFTER_CURRENT(meta, recno))
  431. ret = __qam_fclose(dbp, pg);
  432. (void)__LPUT(dbc, lock);
  433. }
  434. err:
  435. /* Release the meta page. */
  436. if ((t_ret
  437.      = memp_fput(dbp->mpf, meta, DB_MPOOL_DIRTY)) != 0 && ret == 0)
  438. ret = t_ret;
  439. done:
  440. /* Discard the cursor. */
  441. if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
  442. ret = t_ret;
  443. return (ret);
  444. }
  445. /*
  446.  * __qam_c_del --
  447.  * Qam cursor->am_del function
  448.  */
  449. static int
  450. __qam_c_del(dbc)
  451. DBC *dbc;
  452. {
  453. QUEUE_CURSOR *cp;
  454. DB *dbp;
  455. DBT data;
  456. DB_LOCK lock;
  457. PAGE *pagep;
  458. QAMDATA *qp;
  459. QMETA *meta;
  460. db_pgno_t pg;
  461. int exact, ret, t_ret;
  462. dbp = dbc->dbp;
  463. cp = (QUEUE_CURSOR *)dbc->internal;
  464. pg = ((QUEUE *)dbp->q_internal)->q_meta;
  465. if ((ret = __db_lget(dbc, 0, pg,  DB_LOCK_READ, 0, &lock)) != 0)
  466. return (ret);
  467. if ((ret = memp_fget(dbp->mpf, &pg, 0, &meta)) != 0) {
  468. /* We did not fetch it, we can release the lock. */
  469. (void)__LPUT(dbc, lock);
  470. return (ret);
  471. }
  472. if (QAM_NOT_VALID(meta, cp->recno))
  473. ret = DB_NOTFOUND;
  474. /* Don't hold the meta page long term. */
  475. if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
  476. ret = t_ret;
  477. if ((t_ret = memp_fput(dbp->mpf, meta, 0)) != 0 && ret == 0)
  478. ret = t_ret;
  479. if (ret != 0)
  480. return (ret);
  481. if ((ret = __db_lget(dbc,
  482.     0, cp->recno, DB_LOCK_WRITE, DB_LOCK_RECORD, &lock)) != 0)
  483. return (ret);
  484. cp->lock_mode = DB_LOCK_WRITE;
  485. /* Find the record ; delete only deletes exact matches. */
  486. if ((ret = __qam_position(dbc,
  487.     &cp->recno, QAM_WRITE, &exact)) != 0) {
  488. cp->lock = lock;
  489. return (ret);
  490. }
  491. if (!exact) {
  492. ret = DB_NOTFOUND;
  493. goto err1;
  494. }
  495. pagep = cp->page;
  496. qp = QAM_GET_RECORD(dbp, pagep, cp->indx);
  497. if (DB_LOGGING(dbc)) {
  498. if (((QUEUE *)dbp->q_internal)->page_ext == 0
  499.     || ((QUEUE *)dbp->q_internal)->re_len == 0) {
  500. if ((ret =
  501.     __qam_del_log(dbp->dbenv,
  502.     dbc->txn, &LSN(pagep), 0,
  503.     dbp->log_fileid, &LSN(pagep),
  504.     pagep->pgno, cp->indx, cp->recno)) != 0)
  505. goto err1;
  506. } else {
  507. data.size = ((QUEUE *)dbp->q_internal)->re_len;
  508. data.data = qp->data;
  509. if ((ret =
  510.     __qam_delext_log(dbp->dbenv, dbc->txn,
  511.     &LSN(pagep), 0, dbp->log_fileid, &LSN(pagep),
  512.     pagep->pgno, cp->indx, cp->recno, &data)) != 0)
  513. goto err1;
  514. }
  515. }
  516. F_CLR(qp, QAM_VALID);
  517. err1:
  518. if ((t_ret = __qam_fput(
  519.     dbp, cp->pgno, cp->page, ret == 0 ? DB_MPOOL_DIRTY : 0)) != 0)
  520. return (ret ? ret : t_ret);
  521. cp->page = NULL;
  522. /* Doing record locking, release the page lock */
  523. if ((t_ret = __LPUT(dbc, cp->lock)) != 0) {
  524. cp->lock = lock;
  525. return (ret ? ret : t_ret);
  526. }
  527. cp->lock = lock;
  528. return (ret);
  529. }
  530. /*
  531.  * __qam_delete --
  532.  * Queue db->del function.
  533.  *
  534.  * PUBLIC: int __qam_delete __P((DB *, DB_TXN *, DBT *, u_int32_t));
  535.  */
  536. int
  537. __qam_delete(dbp, txn, key, flags)
  538. DB *dbp;
  539. DB_TXN *txn;
  540. DBT *key;
  541. u_int32_t flags;
  542. {
  543. QUEUE_CURSOR *cp;
  544. DBC *dbc;
  545. int ret, t_ret;
  546. PANIC_CHECK(dbp->dbenv);
  547. DB_CHECK_TXN(dbp, txn);
  548. /* Check for invalid flags. */
  549. if ((ret =
  550.     __db_delchk(dbp, key, flags, F_ISSET(dbp, DB_AM_RDONLY))) != 0)
  551. return (ret);
  552. /* Acquire a cursor. */
  553. if ((ret = dbp->cursor(dbp, txn, &dbc, DB_WRITELOCK)) != 0)
  554. return (ret);
  555. DEBUG_LWRITE(dbc, txn, "qam_delete", key, NULL, flags);
  556. cp = (QUEUE_CURSOR *)dbc->internal;
  557. if ((ret = __qam_getno(dbp, key, &cp->recno)) != 0)
  558. goto err;
  559. ret = __qam_c_del(dbc);
  560. /* Release the cursor. */
  561. err: if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
  562. ret = t_ret;
  563. return (ret);
  564. }
  565. #ifdef DEBUG_WOP
  566. #define QDEBUG
  567. #endif
  568. /*
  569.  * __qam_c_get --
  570.  * Queue cursor->c_get function.
  571.  */
  572. static int
  573. __qam_c_get(dbc, key, data, flags, pgnop)
  574. DBC *dbc;
  575. DBT *key, *data;
  576. u_int32_t flags;
  577. db_pgno_t *pgnop;
  578. {
  579. DB *dbp;
  580. DB_LOCK lock, pglock, metalock, save_lock;
  581. DBT tmp;
  582. PAGE *pg;
  583. QAMDATA *qp;
  584. QMETA *meta;
  585. QUEUE *t;
  586. QUEUE_CURSOR *cp;
  587. db_indx_t save_indx;
  588. db_lockmode_t lock_mode;
  589. db_pgno_t metapno, save_page;
  590. db_recno_t current, first, save_recno;
  591. qam_position_mode mode;
  592. u_int32_t rec_extent;
  593. int exact, is_first, locked, ret, t_ret, wait, with_delete;
  594. int put_mode, meta_dirty, retrying, skip_again, wrapped;
  595. cp = (QUEUE_CURSOR *)dbc->internal;
  596. dbp = dbc->dbp;
  597. PANIC_CHECK(dbp->dbenv);
  598. wait = 0;
  599. with_delete = 0;
  600. retrying = 0;
  601. rec_extent = 0;
  602. lock_mode = DB_LOCK_READ;
  603. mode = QAM_READ;
  604. put_mode = 0;
  605. t_ret = 0;
  606. *pgnop = 0;
  607. pg = NULL;
  608. skip_again = 0;
  609. if (F_ISSET(dbc, DBC_RMW)) {
  610. lock_mode = DB_LOCK_WRITE;
  611. mode = QAM_WRITE;
  612. }
  613. if (flags == DB_CONSUME_WAIT) {
  614. wait = 1;
  615. flags = DB_CONSUME;
  616. }
  617. if (flags == DB_CONSUME) {
  618. DB_CHECK_TXN(dbp, dbc->txn);
  619. with_delete = 1;
  620. flags = DB_FIRST;
  621. lock_mode = DB_LOCK_WRITE;
  622. mode = QAM_CONSUME;
  623. }
  624. DEBUG_LREAD(dbc, dbc->txn, "qam_c_get",
  625.     flags == DB_SET || flags == DB_SET_RANGE ? key : NULL, NULL, flags);
  626. is_first = 0;
  627. t = (QUEUE *)dbp->q_internal;
  628. /* get the meta page */
  629. metapno = t->q_meta;
  630. if ((ret = __db_lget(dbc, 0, metapno, lock_mode, 0, &metalock)) != 0)
  631. return (ret);
  632. locked = 1;
  633. if ((ret = memp_fget(dbp->mpf, &metapno, 0, &meta)) != 0) {
  634. /* We did not fetch it, we can release the lock. */
  635. (void)__LPUT(dbc, metalock);
  636. return (ret);
  637. }
  638. first = 0;
  639. /* Make lint and friends happy. */
  640. meta_dirty = 0;
  641. /* Release any previous lock if not in a transaction. */
  642. if (cp->lock.off != LOCK_INVALID) {
  643. (void)__TLPUT(dbc, cp->lock);
  644. cp->lock.off = LOCK_INVALID;
  645. }
  646. retry: /* Update the record number. */
  647. switch (flags) {
  648. case DB_CURRENT:
  649. break;
  650. case DB_NEXT_DUP:
  651. ret = DB_NOTFOUND;
  652. goto err;
  653. /* NOTREACHED */
  654. case DB_NEXT:
  655. case DB_NEXT_NODUP:
  656. if (cp->recno != RECNO_OOB) {
  657. ++cp->recno;
  658. /* Wrap around, skipping zero. */
  659. if (cp->recno == RECNO_OOB)
  660. cp->recno++;
  661. break;
  662. }
  663. /* FALLTHROUGH */
  664. case DB_FIRST:
  665. flags = DB_NEXT;
  666. is_first = 1;
  667. /* get the first record number */
  668. cp->recno = first = meta->first_recno;
  669. break;
  670. case DB_PREV:
  671. case DB_PREV_NODUP:
  672. if (cp->recno != RECNO_OOB) {
  673. if (QAM_BEFORE_FIRST(meta, cp->recno)
  674.     || cp->recno == meta->first_recno) {
  675. ret = DB_NOTFOUND;
  676. goto err;
  677. }
  678. --cp->recno;
  679. /* Wrap around, skipping zero. */
  680. if (cp->recno == RECNO_OOB)
  681. --cp->recno;
  682. break;
  683. }
  684. /* FALLTHROUGH */
  685. case DB_LAST:
  686. if (meta->first_recno == meta->cur_recno) {
  687. ret = DB_NOTFOUND;
  688. goto err;
  689. }
  690. cp->recno = meta->cur_recno - 1;
  691. if (cp->recno == RECNO_OOB)
  692. cp->recno--;
  693. break;
  694. case DB_GET_BOTH:
  695. case DB_SET:
  696. case DB_SET_RANGE:
  697. if ((ret = __qam_getno(dbp, key, &cp->recno)) != 0)
  698. goto err;
  699. break;
  700. default:
  701. ret = __db_unknown_flag(dbp->dbenv, "__qam_c_get", flags);
  702. goto err;
  703. }
  704. /*
  705.  * Check to see if we are out of data.  Current points to
  706.  * the first free slot.
  707.  */
  708. if (cp->recno == meta->cur_recno ||
  709.     QAM_AFTER_CURRENT(meta, cp->recno)) {
  710. ret = DB_NOTFOUND;
  711. pg = NULL;
  712. if (wait) {
  713. flags = DB_FIRST;
  714. /*
  715.  * If first is not set, then we skipped a
  716.  * locked record, go back and find it.
  717.  * If we find a locked record again
  718.  * wait for it.
  719.  */
  720. if (first == 0) {
  721. retrying = 1;
  722. goto retry;
  723. }
  724. if (CDB_LOCKING(dbp->dbenv)) {
  725. if ((ret = lock_get(dbp->dbenv, dbc->locker,
  726.     DB_LOCK_SWITCH, &dbc->lock_dbt,
  727.     DB_LOCK_WAIT, &dbc->mylock)) != 0)
  728. goto err;
  729. if ((ret = lock_get(dbp->dbenv, dbc->locker,
  730.     DB_LOCK_UPGRADE, &dbc->lock_dbt, DB_LOCK_WRITE,
  731.     &dbc->mylock)) != 0)
  732. goto err;
  733. goto retry;
  734. }
  735. /*
  736.  * Wait for someone to update the meta page.
  737.  * This will probably mean there is something
  738.  * in the queue.  We then go back up and
  739.  * try again.
  740.  */
  741. if (locked == 0) {
  742. if ((ret = __db_lget( dbc,
  743.     0, metapno, lock_mode, 0, &metalock)) != 0)
  744. goto err;
  745. locked = 1;
  746. if (cp->recno != RECNO_OOB &&
  747.     !QAM_AFTER_CURRENT(meta, cp->recno))
  748. goto retry;
  749. }
  750. if ((ret = __db_lget(dbc, 0, metapno,
  751.     DB_LOCK_WAIT, DB_LOCK_SWITCH, &metalock)) != 0)
  752. goto err;
  753. if ((ret = lock_get(dbp->dbenv, dbc->locker,
  754.     DB_LOCK_UPGRADE, &dbc->lock_dbt, DB_LOCK_WRITE,
  755.     &metalock)) != 0)
  756. goto err;
  757. locked = 1;
  758. goto retry;
  759. }
  760. goto err;
  761. }
  762. /* Don't hold the meta page long term. */
  763. if (locked) {
  764. if ((ret = __LPUT(dbc, metalock)) != 0)
  765. goto err;
  766. locked = 0;
  767. }
  768. /* Lock the record. */
  769. if ((ret = __db_lget(dbc, 0, cp->recno, lock_mode,
  770.     (with_delete && !retrying) ?
  771.     DB_LOCK_NOWAIT | DB_LOCK_RECORD : DB_LOCK_RECORD,
  772.     &lock)) == DB_LOCK_NOTGRANTED && with_delete) {
  773. #ifdef QDEBUG
  774. __db_logmsg(dbp->dbenv,
  775.     dbc->txn, "Queue S", 0, "%x %d %d %d",
  776.     dbc->locker, cp->recno, first, meta->first_recno);
  777. #endif
  778. first = 0;
  779. goto retry;
  780. }
  781. if (ret != 0)
  782. goto err;
  783. /*
  784.  * In the DB_FIRST or DB_LAST cases we must wait and then start over
  785.  * since the first/last may have moved while we slept.
  786.  * We release our locks and try again.
  787.  */
  788. if ((!with_delete && is_first) || flags == DB_LAST) {
  789. if ((ret =
  790.     __db_lget(dbc, 0, metapno, lock_mode, 0, &metalock)) != 0)
  791. goto err;
  792. if (cp->recno !=
  793.     (is_first ? meta->first_recno : (meta->cur_recno - 1))) {
  794. __LPUT(dbc, lock);
  795. if (is_first)
  796. flags = DB_FIRST;
  797. locked = 1;
  798. goto retry;
  799. }
  800. /* Don't hold the meta page long term. */
  801. if ((ret = __LPUT(dbc, metalock)) != 0)
  802. goto err;
  803. }
  804. /* Position the cursor on the record. */
  805. if ((ret = __qam_position(dbc, &cp->recno, mode, &exact)) != 0) {
  806. /* We cannot get the page, release the record lock. */
  807. (void)__LPUT(dbc, lock);
  808. goto err;
  809. }
  810. pg = cp->page;
  811. pglock = cp->lock;
  812. cp->lock = lock;
  813. cp->lock_mode = lock_mode;
  814. if (!exact) {
  815. if (flags == DB_NEXT || flags == DB_NEXT_NODUP
  816.     || flags == DB_PREV || flags == DB_PREV_NODUP
  817.     || flags == DB_LAST) {
  818. /* Release locks and try again. */
  819. if (pg != NULL)
  820. (void)__qam_fput(dbp, cp->pgno, pg, 0);
  821. cp->page = pg = NULL;
  822. (void)__LPUT(dbc, pglock);
  823. (void)__LPUT(dbc, cp->lock);
  824. if (flags == DB_LAST)
  825. flags = DB_PREV;
  826. if (!with_delete)
  827. is_first = 0;
  828. retrying = 0;
  829. goto retry;
  830. }
  831. /* this is for the SET and SET_RANGE cases */
  832. ret = DB_KEYEMPTY;
  833. goto err1;
  834. }
  835. /* Return the key if the user didn't give us one. */
  836. if (key != NULL && flags != DB_SET && flags != DB_GET_BOTH &&
  837.     (ret = __db_retcopy(dbp, key, &cp->recno, sizeof(cp->recno),
  838.     &dbc->rkey.data, &dbc->rkey.ulen)) != 0)
  839. goto err1;
  840. if (key != NULL)
  841. F_SET(key, DB_DBT_ISSET);
  842. qp = QAM_GET_RECORD(dbp, pg, cp->indx);
  843. /* Return the data item. */
  844. if (flags == DB_GET_BOTH) {
  845. /*
  846.  * Need to compare
  847.  */
  848. tmp.data = qp->data;
  849. tmp.size = t->re_len;
  850. if ((ret = __bam_defcmp(dbp, data, &tmp)) != 0) {
  851. ret = DB_NOTFOUND;
  852. goto err1;
  853. }
  854. }
  855. if (data != NULL && (ret = __db_retcopy(dbp, data,
  856.     qp->data, t->re_len, &dbc->rdata.data, &dbc->rdata.ulen)) != 0)
  857. goto err1;
  858. if (data != NULL)
  859. F_SET(data, DB_DBT_ISSET);
  860. /* Finally, if we are doing DB_CONSUME mark the record. */
  861. if (with_delete) {
  862. if (DB_LOGGING(dbc)) {
  863. if (t->page_ext == 0 || t->re_len == 0) {
  864. if ((ret = __qam_del_log(dbp->dbenv, dbc->txn,
  865.     &LSN(pg), 0, dbp->log_fileid, &LSN(pg),
  866.     pg->pgno, cp->indx, cp->recno)) != 0)
  867. goto err1;
  868. } else {
  869. tmp.data = qp->data;
  870. tmp.size = t->re_len;
  871. if ((ret =
  872.    __qam_delext_log(dbp->dbenv, dbc->txn,
  873.    &LSN(pg), 0, dbp->log_fileid, &LSN(pg),
  874.    pg->pgno, cp->indx, cp->recno, &tmp)) != 0)
  875. goto err1;
  876. }
  877. }
  878. F_CLR(qp, QAM_VALID);
  879. put_mode = DB_MPOOL_DIRTY;
  880. if ((ret = __LPUT(dbc, pglock)) != 0)
  881. goto err;
  882. /*
  883.  * Now we need to update the metapage
  884.  * first pointer. If we have deleted
  885.  * the record that is pointed to by
  886.  * first_recno then we move it as far
  887.  * forward as we can without blocking.
  888.  * The metapage lock must be held for
  889.  * the whole scan otherwise someone could
  890.  * do a random insert behind where we are
  891.  * looking.
  892.  */
  893. if (locked == 0 && (ret = __db_lget(
  894.     dbc, 0, metapno, lock_mode, 0, &metalock)) != 0)
  895. goto err1;
  896. locked = 1;
  897. #ifdef QDEBUG
  898. __db_logmsg(dbp->dbenv,
  899.     dbc->txn, "Queue D", 0, "%x %d %d %d",
  900.     dbc->locker, cp->recno, first, meta->first_recno);
  901. #endif
  902. /*
  903.  * See if we deleted the "first" record.  If
  904.  * first is zero then we skipped something,
  905.  * see if first_recno has been move passed
  906.  * that to the record that we deleted.
  907.  */
  908. if (first == 0)
  909. first = cp->recno;
  910. if (first != meta->first_recno)
  911. goto done;
  912. save_page = cp->pgno;
  913. save_indx = cp->indx;
  914. save_recno = cp->recno;
  915. save_lock = cp->lock;
  916. /*
  917.  * If we skipped some deleted records, we need to
  918.  * reposition on the first one.  Get a lock
  919.  * in case someone is trying to put it back.
  920.  */
  921. if (first != cp->recno) {
  922. ret = __db_lget(dbc, 0, first, DB_LOCK_READ,
  923.     DB_LOCK_NOWAIT | DB_LOCK_RECORD, &lock);
  924. if (ret == DB_LOCK_NOTGRANTED) {
  925. ret = 0;
  926. goto done;
  927. }
  928. if (ret != 0)
  929. goto err1;
  930. if ((ret =
  931.     __qam_fput(dbp, cp->pgno, cp->page, put_mode)) != 0)
  932. goto err1;
  933. cp->page = NULL;
  934. put_mode = 0;
  935. if ((ret = __qam_position(dbc,
  936.     &first, QAM_READ, &exact)) != 0 || exact != 0) {
  937. (void)__LPUT(dbc, lock);
  938. goto err1;
  939. }
  940. if ((ret =__LPUT(dbc, lock)) != 0)
  941. goto err1;
  942. if ((ret = __LPUT(dbc, cp->lock)) != 0)
  943. goto err1;
  944. }
  945. current = meta->cur_recno;
  946. wrapped = 0;
  947. if (first > current)
  948. wrapped = 1;
  949. rec_extent = meta->page_ext * meta->rec_page;
  950. /* Loop until we find a record or hit current */
  951. for (;;) {
  952. /*
  953.  * Check to see if we are moving off the extent
  954.  * and remove the extent.
  955.  * If we are moving off a page we need to
  956.  * get rid of the buffer.
  957.  * Wait for the lagging readers to move off the
  958.  * page.
  959.  */
  960. if (rec_extent != 0
  961.     && ((exact = first % rec_extent == 0)
  962.     || first % meta->rec_page == 0
  963.     || first == UINT32_T_MAX)) {
  964. if (exact == 1 && (ret = __db_lget(dbc,
  965.     0, cp->pgno, DB_LOCK_WRITE, 0, &cp->lock)) != 0)
  966. break;
  967. #ifdef QDEBUG
  968. __db_logmsg(dbp->dbenv,
  969.     dbc->txn, "Queue R", 0, "%x %d %d %d",
  970.     dbc->locker, cp->pgno, first, meta->first_recno);
  971. #endif
  972. put_mode |= DB_MPOOL_DISCARD;
  973. if ((ret = __qam_fput(dbp,
  974.     cp->pgno, cp->page, put_mode)) != 0)
  975. break;
  976. cp->page = NULL;
  977. if (exact == 1) {
  978. ret = __qam_fremove(dbp, cp->pgno);
  979. t_ret = __LPUT(dbc, cp->lock);
  980. }
  981. if (ret != 0)
  982. break;
  983. if (t_ret != 0) {
  984. ret = t_ret;
  985. break;
  986. }
  987. } else if ((ret =
  988.     __qam_fput(dbp, cp->pgno, cp->page, put_mode)) != 0)
  989. break;
  990. cp->page = NULL;
  991. first++;
  992. if (first == RECNO_OOB) {
  993. wrapped = 0;
  994. first++;
  995. }
  996. /*
  997.  * LOOP EXIT when we come move to the current
  998.  * pointer.
  999.  */
  1000. if (!wrapped && first >= current)
  1001. break;
  1002. ret = __db_lget(dbc, 0, first, DB_LOCK_READ,
  1003.     DB_LOCK_NOWAIT | DB_LOCK_RECORD, &lock);
  1004. if (ret == DB_LOCK_NOTGRANTED) {
  1005. ret = 0;
  1006. break;
  1007. }
  1008. if (ret != 0)
  1009. break;
  1010. if ((ret = __qam_position(dbc,
  1011.     &first, QAM_READ, &exact)) != 0) {
  1012. (void)__LPUT(dbc, lock);
  1013. break;
  1014. }
  1015. put_mode = 0;
  1016. if ((ret =__LPUT(dbc, lock)) != 0
  1017.     || (ret = __LPUT(dbc, cp->lock)) != 0 ||exact) {
  1018. if ((t_ret = __qam_fput(dbp, cp->pgno,
  1019.     cp->page, put_mode)) != 0 && ret == 0)
  1020. ret = t_ret;
  1021. cp->page = NULL;
  1022. break;
  1023. }
  1024. }
  1025. cp->pgno = save_page;
  1026. cp->indx = save_indx;
  1027. cp->recno = save_recno;
  1028. cp->lock = save_lock;
  1029. /*
  1030.  * We have advanced as far as we can.
  1031.  * Advance first_recno to this point.
  1032.  */
  1033. if (meta->first_recno != first) {
  1034. #ifdef QDEBUG
  1035. __db_logmsg(dbp->dbenv, dbc->txn, "Queue M",
  1036.     0, "%x %d %d %d", dbc->locker, cp->recno,
  1037.     first, meta->first_recno);
  1038. #endif
  1039. if (DB_LOGGING(dbc))
  1040. if ((ret =
  1041.      __qam_incfirst_log(dbp->dbenv,
  1042.      dbc->txn, &meta->dbmeta.lsn, 0,
  1043.      dbp->log_fileid, cp->recno)) != 0)
  1044. goto err;
  1045. meta->first_recno = first;
  1046. meta_dirty = 1;
  1047. }
  1048. }
  1049. done:
  1050. err1: if (cp->page != NULL) {
  1051. t_ret = __qam_fput(dbp, cp->pgno, cp->page, put_mode);
  1052. if (!ret)
  1053. ret = t_ret;
  1054. /* Doing record locking, release the page lock */
  1055. t_ret = __LPUT(dbc, pglock);
  1056. cp->page = NULL;
  1057. }
  1058. err: if (!ret)
  1059. ret = t_ret;
  1060. if (meta) {
  1061. /* release the meta page */
  1062. t_ret = memp_fput(
  1063.     dbp->mpf, meta, meta_dirty ? DB_MPOOL_DIRTY : 0);
  1064. if (!ret)
  1065. ret = t_ret;
  1066. /* Don't hold the meta page long term. */
  1067. if (locked)
  1068. t_ret = __LPUT(dbc, metalock);
  1069. }
  1070. DB_ASSERT(metalock.off == LOCK_INVALID);
  1071. /*
  1072.  * There is no need to keep the record locked if we are
  1073.  * not in a transaction.
  1074.  */
  1075. if (t_ret == 0)
  1076. t_ret = __TLPUT(dbc, cp->lock);
  1077. return (ret ? ret : t_ret);
  1078. }
  1079. /*
  1080.  * __qam_c_close --
  1081.  * Close down the cursor from a single use.
  1082.  */
  1083. static int
  1084. __qam_c_close(dbc, root_pgno, rmroot)
  1085. DBC *dbc;
  1086. db_pgno_t root_pgno;
  1087. int *rmroot;
  1088. {
  1089. QUEUE_CURSOR *cp;
  1090. COMPQUIET(root_pgno, 0);
  1091. COMPQUIET(rmroot, NULL);
  1092. cp = (QUEUE_CURSOR *)dbc->internal;
  1093. /* Discard any locks not acquired inside of a transaction. */
  1094. if (cp->lock.off != LOCK_INVALID) {
  1095. (void)__TLPUT(dbc, cp->lock);
  1096. cp->lock.off = LOCK_INVALID;
  1097. }
  1098. cp->page = NULL;
  1099. cp->pgno = PGNO_INVALID;
  1100. cp->indx = 0;
  1101. cp->lock.off = LOCK_INVALID;
  1102. cp->lock_mode = DB_LOCK_NG;
  1103. cp->recno = RECNO_OOB;
  1104. cp->flags = 0;
  1105. return (0);
  1106. }
  1107. /*
  1108.  * __qam_c_dup --
  1109.  * Duplicate a queue cursor, such that the new one holds appropriate
  1110.  * locks for the position of the original.
  1111.  *
  1112.  * PUBLIC: int __qam_c_dup __P((DBC *, DBC *));
  1113.  */
  1114. int
  1115. __qam_c_dup(orig_dbc, new_dbc)
  1116. DBC *orig_dbc, *new_dbc;
  1117. {
  1118. QUEUE_CURSOR *orig, *new;
  1119. orig = (QUEUE_CURSOR *)orig_dbc->internal;
  1120. new = (QUEUE_CURSOR *)new_dbc->internal;
  1121. new->recno = orig->recno;
  1122. /* reget the long term lock if we are not in a xact */
  1123. if (orig_dbc->txn != NULL ||
  1124.     !STD_LOCKING(orig_dbc) || orig->lock.off == LOCK_INVALID)
  1125. return (0);
  1126. return (__db_lget(new_dbc,
  1127.     0, new->recno, new->lock_mode, DB_LOCK_RECORD, &new->lock));
  1128. }
  1129. /*
  1130.  * __qam_c_init
  1131.  *
  1132.  * PUBLIC: int __qam_c_init __P((DBC *));
  1133.  */
  1134. int
  1135. __qam_c_init(dbc)
  1136. DBC *dbc;
  1137. {
  1138. QUEUE_CURSOR *cp;
  1139. DB *dbp;
  1140. int ret;
  1141. dbp = dbc->dbp;
  1142. /* Allocate the internal structure. */
  1143. cp = (QUEUE_CURSOR *)dbc->internal;
  1144. if (cp == NULL) {
  1145. if ((ret =
  1146.     __os_calloc(dbp->dbenv, 1, sizeof(QUEUE_CURSOR), &cp)) != 0)
  1147. return (ret);
  1148. dbc->internal = (DBC_INTERNAL *)cp;
  1149. }
  1150. /* Initialize methods. */
  1151. dbc->c_close = __db_c_close;
  1152. dbc->c_count = __db_c_count;
  1153. dbc->c_del = __db_c_del;
  1154. dbc->c_dup = __db_c_dup;
  1155. dbc->c_get = __db_c_get;
  1156. dbc->c_put = __db_c_put;
  1157. dbc->c_am_close = __qam_c_close;
  1158. dbc->c_am_del = __qam_c_del;
  1159. dbc->c_am_destroy = __qam_c_destroy;
  1160. dbc->c_am_get = __qam_c_get;
  1161. dbc->c_am_put = __qam_c_put;
  1162. dbc->c_am_writelock = NULL;
  1163. return (0);
  1164. }
  1165. /*
  1166.  * __qam_c_destroy --
  1167.  * Close a single cursor -- internal version.
  1168.  */
  1169. static int
  1170. __qam_c_destroy(dbc)
  1171. DBC *dbc;
  1172. {
  1173. /* Discard the structures. */
  1174. __os_free(dbc->internal, sizeof(QUEUE_CURSOR));
  1175. return (0);
  1176. }
  1177. /*
  1178.  * __qam_getno --
  1179.  * Check the user's record number.
  1180.  */
  1181. static int
  1182. __qam_getno(dbp, key, rep)
  1183. DB *dbp;
  1184. const DBT *key;
  1185. db_recno_t *rep;
  1186. {
  1187. if ((*rep = *(db_recno_t *)key->data) == 0) {
  1188. __db_err(dbp->dbenv, "illegal record number of 0");
  1189. return (EINVAL);
  1190. }
  1191. return (0);
  1192. }