mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
155e78f014
BitKeeper/deleted/.del-ex_access.wpj~3df6ae8c99bf7c5f: Delete: bdb/build_vxworks/ex_access/ex_access.wpj BitKeeper/deleted/.del-ex_btrec.wpj~a7622f1c6f432dc6: Delete: bdb/build_vxworks/ex_btrec/ex_btrec.wpj BitKeeper/deleted/.del-ex_dbclient.wpj~7345440f3b204cdd: Delete: bdb/build_vxworks/ex_dbclient/ex_dbclient.wpj BitKeeper/deleted/.del-ex_env.wpj~fbe1ab10b04e8b74: Delete: bdb/build_vxworks/ex_env/ex_env.wpj BitKeeper/deleted/.del-ex_mpool.wpj~4479cfd5c45f327d: Delete: bdb/build_vxworks/ex_mpool/ex_mpool.wpj BitKeeper/deleted/.del-ex_tpcb.wpj~f78093006e14bf41: Delete: bdb/build_vxworks/ex_tpcb/ex_tpcb.wpj BitKeeper/deleted/.del-db_buildall.dsp~bd749ff6da11682: Delete: bdb/build_win32/db_buildall.dsp BitKeeper/deleted/.del-cxx_app.cpp~ad8df8e0791011ed: Delete: bdb/cxx/cxx_app.cpp BitKeeper/deleted/.del-cxx_log.cpp~a50ff3118fe06952: Delete: bdb/cxx/cxx_log.cpp BitKeeper/deleted/.del-cxx_table.cpp~ecd751e79b055556: Delete: bdb/cxx/cxx_table.cpp BitKeeper/deleted/.del-namemap.txt~796a3acd3885d8fd: Delete: bdb/cxx/namemap.txt BitKeeper/deleted/.del-Design.fileop~3ca4da68f1727373: Delete: bdb/db/Design.fileop BitKeeper/deleted/.del-db185_int.h~61bee3736e7959ef: Delete: bdb/db185/db185_int.h BitKeeper/deleted/.del-acconfig.h~411e8854d67ad8b5: Delete: bdb/dist/acconfig.h BitKeeper/deleted/.del-mutex.m4~a13383cde18a64e1: Delete: bdb/dist/aclocal/mutex.m4 BitKeeper/deleted/.del-options.m4~b9d0ca637213750a: Delete: bdb/dist/aclocal/options.m4 BitKeeper/deleted/.del-programs.m4~3ce7890b47732b30: Delete: bdb/dist/aclocal/programs.m4 BitKeeper/deleted/.del-tcl.m4~f944e2db93c3b6db: Delete: bdb/dist/aclocal/tcl.m4 BitKeeper/deleted/.del-types.m4~59cae158c9a32cff: Delete: bdb/dist/aclocal/types.m4 BitKeeper/deleted/.del-script~d38f6d3a4f159cb4: Delete: bdb/dist/build/script BitKeeper/deleted/.del-configure.in~ac795a92c8fe049c: Delete: bdb/dist/configure.in BitKeeper/deleted/.del-ltconfig~66bbd007d8024af: Delete: bdb/dist/ltconfig BitKeeper/deleted/.del-rec_ctemp~a28554362534f00a: Delete: bdb/dist/rec_ctemp BitKeeper/deleted/.del-s_tcl~2ffe4326459fcd9f: Delete: bdb/dist/s_tcl BitKeeper/deleted/.del-.IGNORE_ME~d8148b08fa7d5d15: Delete: bdb/dist/template/.IGNORE_ME BitKeeper/deleted/.del-btree.h~179f2aefec1753d: Delete: bdb/include/btree.h BitKeeper/deleted/.del-cxx_int.h~6b649c04766508f8: Delete: bdb/include/cxx_int.h BitKeeper/deleted/.del-db.src~6b433ae615b16a8d: Delete: bdb/include/db.src BitKeeper/deleted/.del-db_185.h~ad8b373d9391d35c: Delete: bdb/include/db_185.h BitKeeper/deleted/.del-db_am.h~a714912b6b75932f: Delete: bdb/include/db_am.h BitKeeper/deleted/.del-db_cxx.h~fcafadf45f5d19e9: Delete: bdb/include/db_cxx.h BitKeeper/deleted/.del-db_dispatch.h~6844f20f7eb46904: Delete: bdb/include/db_dispatch.h BitKeeper/deleted/.del-db_int.src~419a3f48b6a01da7: Delete: bdb/include/db_int.src BitKeeper/deleted/.del-db_join.h~76f9747a42c3399a: Delete: bdb/include/db_join.h BitKeeper/deleted/.del-db_page.h~e302ca3a4db3abdc: Delete: bdb/include/db_page.h BitKeeper/deleted/.del-db_server_int.h~e1d20b6ba3bca1ab: Delete: bdb/include/db_server_int.h BitKeeper/deleted/.del-db_shash.h~5fbf2d696fac90f3: Delete: bdb/include/db_shash.h BitKeeper/deleted/.del-db_swap.h~1e60887550864a59: Delete: bdb/include/db_swap.h BitKeeper/deleted/.del-db_upgrade.h~c644eee73701fc8d: Delete: bdb/include/db_upgrade.h BitKeeper/deleted/.del-db_verify.h~b8d6c297c61f342e: Delete: bdb/include/db_verify.h BitKeeper/deleted/.del-debug.h~dc2b4f2cf27ccebc: Delete: bdb/include/debug.h BitKeeper/deleted/.del-hash.h~2aaa548b28882dfb: Delete: bdb/include/hash.h BitKeeper/deleted/.del-lock.h~a761c1b7de57b77f: Delete: bdb/include/lock.h BitKeeper/deleted/.del-log.h~ff20184238e35e4d: Delete: bdb/include/log.h BitKeeper/deleted/.del-mp.h~7e317597622f3411: Delete: bdb/include/mp.h BitKeeper/deleted/.del-mutex.h~d3ae7a2977a68137: Delete: bdb/include/mutex.h BitKeeper/deleted/.del-os.h~91867cc8757cd0e3: Delete: bdb/include/os.h BitKeeper/deleted/.del-os_jump.h~e1b939fa5151d4be: Delete: bdb/include/os_jump.h BitKeeper/deleted/.del-qam.h~6fad0c1b5723d597: Delete: bdb/include/qam.h BitKeeper/deleted/.del-queue.h~4c72c0826c123d5: Delete: bdb/include/queue.h BitKeeper/deleted/.del-region.h~513fe04d977ca0fc: Delete: bdb/include/region.h BitKeeper/deleted/.del-shqueue.h~525fc3e6c2025c36: Delete: bdb/include/shqueue.h BitKeeper/deleted/.del-tcl_db.h~c536fd61a844f23f: Delete: bdb/include/tcl_db.h BitKeeper/deleted/.del-txn.h~c8d94b221ec147e4: Delete: bdb/include/txn.h BitKeeper/deleted/.del-xa.h~ecc466493aae9d9a: Delete: bdb/include/xa.h BitKeeper/deleted/.del-DbRecoveryInit.java~756b52601a0b9023: Delete: bdb/java/src/com/sleepycat/db/DbRecoveryInit.java BitKeeper/deleted/.del-DbTxnRecover.java~74607cba7ab89d6d: Delete: bdb/java/src/com/sleepycat/db/DbTxnRecover.java BitKeeper/deleted/.del-lock_conflict.c~fc5e0f14cf597a2b: Delete: bdb/lock/lock_conflict.c BitKeeper/deleted/.del-log.src~53ac9e7b5cb023f2: Delete: bdb/log/log.src BitKeeper/deleted/.del-log_findckp.c~24287f008916e81f: Delete: bdb/log/log_findckp.c BitKeeper/deleted/.del-log_rec.c~d51711f2cac09297: Delete: bdb/log/log_rec.c BitKeeper/deleted/.del-log_register.c~b40bb4efac75ca15: Delete: bdb/log/log_register.c BitKeeper/deleted/.del-Design~b3d0f179f2767b: Delete: bdb/mp/Design BitKeeper/deleted/.del-os_finit.c~95dbefc6fe79b26c: Delete: bdb/os/os_finit.c BitKeeper/deleted/.del-os_abs.c~df95d1e7db81924: Delete: bdb/os_vxworks/os_abs.c BitKeeper/deleted/.del-os_finit.c~803b484bdb9d0122: Delete: bdb/os_vxworks/os_finit.c BitKeeper/deleted/.del-os_map.c~3a6d7926398b76d3: Delete: bdb/os_vxworks/os_map.c BitKeeper/deleted/.del-os_finit.c~19a227c6d3c78ad: Delete: bdb/os_win32/os_finit.c BitKeeper/deleted/.del-log-corruption.patch~1cf2ecc7c6408d5d: Delete: bdb/patches/log-corruption.patch BitKeeper/deleted/.del-Btree.pm~af6d0c5eaed4a98e: Delete: bdb/perl.BerkeleyDB/BerkeleyDB/Btree.pm BitKeeper/deleted/.del-BerkeleyDB.pm~7244036d4482643: Delete: bdb/perl.BerkeleyDB/BerkeleyDB.pm BitKeeper/deleted/.del-BerkeleyDB.pod~e7b18fd6132448e3: Delete: bdb/perl.BerkeleyDB/BerkeleyDB.pod BitKeeper/deleted/.del-Hash.pm~10292a26c06a5c95: Delete: bdb/perl.BerkeleyDB/BerkeleyDB/Hash.pm BitKeeper/deleted/.del-BerkeleyDB.pod.P~79f76a1495eda203: Delete: bdb/perl.BerkeleyDB/BerkeleyDB.pod.P BitKeeper/deleted/.del-BerkeleyDB.xs~80c99afbd98e392c: Delete: bdb/perl.BerkeleyDB/BerkeleyDB.xs BitKeeper/deleted/.del-Changes~729c1891efa60de9: Delete: bdb/perl.BerkeleyDB/Changes BitKeeper/deleted/.del-MANIFEST~63a1e34aecf157a0: Delete: bdb/perl.BerkeleyDB/MANIFEST BitKeeper/deleted/.del-Makefile.PL~c68797707d8df87a: Delete: bdb/perl.BerkeleyDB/Makefile.PL BitKeeper/deleted/.del-README~5f2f579b1a241407: Delete: bdb/perl.BerkeleyDB/README BitKeeper/deleted/.del-Todo~dca3c66c193adda9: Delete: bdb/perl.BerkeleyDB/Todo BitKeeper/deleted/.del-config.in~ae81681e450e0999: Delete: bdb/perl.BerkeleyDB/config.in BitKeeper/deleted/.del-dbinfo~28ad67d83be4f68e: Delete: bdb/perl.BerkeleyDB/dbinfo BitKeeper/deleted/.del-mkconsts~543ab60669c7a04e: Delete: bdb/perl.BerkeleyDB/mkconsts BitKeeper/deleted/.del-mkpod~182c0ca54e439afb: Delete: bdb/perl.BerkeleyDB/mkpod BitKeeper/deleted/.del-5.004~e008cb5a48805543: Delete: bdb/perl.BerkeleyDB/patches/5.004 BitKeeper/deleted/.del-irix_6_5.pl~61662bb08afcdec8: Delete: bdb/perl.BerkeleyDB/hints/irix_6_5.pl BitKeeper/deleted/.del-solaris.pl~6771e7182394e152: Delete: bdb/perl.BerkeleyDB/hints/solaris.pl BitKeeper/deleted/.del-typemap~783b8f5295b05f3d: Delete: bdb/perl.BerkeleyDB/typemap BitKeeper/deleted/.del-5.004_01~6081ce2fff7b0bc: Delete: bdb/perl.BerkeleyDB/patches/5.004_01 BitKeeper/deleted/.del-5.004_02~87214eac35ad9e6: Delete: bdb/perl.BerkeleyDB/patches/5.004_02 BitKeeper/deleted/.del-5.004_03~9a672becec7cb40f: Delete: bdb/perl.BerkeleyDB/patches/5.004_03 BitKeeper/deleted/.del-5.004_04~e326cb51af09d154: Delete: bdb/perl.BerkeleyDB/patches/5.004_04 BitKeeper/deleted/.del-5.004_05~7ab457a1e41a92fe: Delete: bdb/perl.BerkeleyDB/patches/5.004_05 BitKeeper/deleted/.del-5.005~f9e2d59b5964cd4b: Delete: bdb/perl.BerkeleyDB/patches/5.005 BitKeeper/deleted/.del-5.005_01~3eb9fb7b5842ea8e: Delete: bdb/perl.BerkeleyDB/patches/5.005_01 BitKeeper/deleted/.del-5.005_02~67477ce0bef717cb: Delete: bdb/perl.BerkeleyDB/patches/5.005_02 BitKeeper/deleted/.del-5.005_03~c4c29a1fb21e290a: Delete: bdb/perl.BerkeleyDB/patches/5.005_03 BitKeeper/deleted/.del-5.6.0~e1fb9897d124ee22: Delete: bdb/perl.BerkeleyDB/patches/5.6.0 BitKeeper/deleted/.del-btree.t~e4a1a3c675ddc406: Delete: bdb/perl.BerkeleyDB/t/btree.t BitKeeper/deleted/.del-db-3.0.t~d2c60991d84558f2: Delete: bdb/perl.BerkeleyDB/t/db-3.0.t BitKeeper/deleted/.del-db-3.1.t~6ee88cd13f55e018: Delete: bdb/perl.BerkeleyDB/t/db-3.1.t BitKeeper/deleted/.del-db-3.2.t~f73b6461f98fd1cf: Delete: bdb/perl.BerkeleyDB/t/db-3.2.t BitKeeper/deleted/.del-destroy.t~cc6a2ae1980a2ecd: Delete: bdb/perl.BerkeleyDB/t/destroy.t BitKeeper/deleted/.del-env.t~a8604a4499c4bd07: Delete: bdb/perl.BerkeleyDB/t/env.t BitKeeper/deleted/.del-examples.t~2571b77c3cc75574: Delete: bdb/perl.BerkeleyDB/t/examples.t BitKeeper/deleted/.del-examples.t.T~8228bdd75ac78b88: Delete: bdb/perl.BerkeleyDB/t/examples.t.T BitKeeper/deleted/.del-examples3.t.T~66a186897a87026d: Delete: bdb/perl.BerkeleyDB/t/examples3.t.T BitKeeper/deleted/.del-examples3.t~fe3822ba2f2d7f83: Delete: bdb/perl.BerkeleyDB/t/examples3.t BitKeeper/deleted/.del-filter.t~f87b045c1b708637: Delete: bdb/perl.BerkeleyDB/t/filter.t BitKeeper/deleted/.del-hash.t~616bfb4d644de3a3: Delete: bdb/perl.BerkeleyDB/t/hash.t BitKeeper/deleted/.del-join.t~29fc39f74a83ca22: Delete: bdb/perl.BerkeleyDB/t/join.t BitKeeper/deleted/.del-mldbm.t~31f5015341eea040: Delete: bdb/perl.BerkeleyDB/t/mldbm.t BitKeeper/deleted/.del-queue.t~8f338034ce44a641: Delete: bdb/perl.BerkeleyDB/t/queue.t BitKeeper/deleted/.del-recno.t~d4ddbd3743add63e: Delete: bdb/perl.BerkeleyDB/t/recno.t BitKeeper/deleted/.del-strict.t~6885cdd2ea71ca2d: Delete: bdb/perl.BerkeleyDB/t/strict.t BitKeeper/deleted/.del-subdb.t~aab62a5d5864c603: Delete: bdb/perl.BerkeleyDB/t/subdb.t BitKeeper/deleted/.del-txn.t~65033b8558ae1216: Delete: bdb/perl.BerkeleyDB/t/txn.t BitKeeper/deleted/.del-unknown.t~f3710458682665e1: Delete: bdb/perl.BerkeleyDB/t/unknown.t BitKeeper/deleted/.del-Changes~436f74a5c414c65b: Delete: bdb/perl.DB_File/Changes BitKeeper/deleted/.del-DB_File.pm~ae0951c6c7665a82: Delete: bdb/perl.DB_File/DB_File.pm BitKeeper/deleted/.del-DB_File.xs~89e49a0b5556f1d8: Delete: bdb/perl.DB_File/DB_File.xs BitKeeper/deleted/.del-DB_File_BS~290fad5dbbb87069: Delete: bdb/perl.DB_File/DB_File_BS BitKeeper/deleted/.del-MANIFEST~90ee581572bdd4ac: Delete: bdb/perl.DB_File/MANIFEST BitKeeper/deleted/.del-Makefile.PL~ac0567bb5a377e38: Delete: bdb/perl.DB_File/Makefile.PL BitKeeper/deleted/.del-README~77e924a5a9bae6b3: Delete: bdb/perl.DB_File/README BitKeeper/deleted/.del-config.in~ab4c2792b86a810b: Delete: bdb/perl.DB_File/config.in BitKeeper/deleted/.del-dbinfo~461c43b30fab2cb: Delete: bdb/perl.DB_File/dbinfo BitKeeper/deleted/.del-dynixptx.pl~50dcddfae25d17e9: Delete: bdb/perl.DB_File/hints/dynixptx.pl BitKeeper/deleted/.del-typemap~55cffb3288a9e587: Delete: bdb/perl.DB_File/typemap BitKeeper/deleted/.del-version.c~a4df0e646f8b3975: Delete: bdb/perl.DB_File/version.c BitKeeper/deleted/.del-5.004_01~d6830d0082702af7: Delete: bdb/perl.DB_File/patches/5.004_01 BitKeeper/deleted/.del-5.004_02~78b082dc80c91031: Delete: bdb/perl.DB_File/patches/5.004_02 BitKeeper/deleted/.del-5.004~4411ec2e3c9e008b: Delete: bdb/perl.DB_File/patches/5.004 BitKeeper/deleted/.del-sco.pl~1e795fe14fe4dcfe: Delete: bdb/perl.DB_File/hints/sco.pl BitKeeper/deleted/.del-5.004_03~33f274648b160d95: Delete: bdb/perl.DB_File/patches/5.004_03 BitKeeper/deleted/.del-5.004_04~8f3d1b3cf18bb20a: Delete: bdb/perl.DB_File/patches/5.004_04 BitKeeper/deleted/.del-5.004_05~9c0f02e7331e142: Delete: bdb/perl.DB_File/patches/5.004_05 BitKeeper/deleted/.del-5.005~c2108cb2e3c8d951: Delete: bdb/perl.DB_File/patches/5.005 BitKeeper/deleted/.del-5.005_01~3b45e9673afc4cfa: Delete: bdb/perl.DB_File/patches/5.005_01 BitKeeper/deleted/.del-5.005_02~9fe5766bb02a4522: Delete: bdb/perl.DB_File/patches/5.005_02 BitKeeper/deleted/.del-5.005_03~ffa1c38c19ae72ea: Delete: bdb/perl.DB_File/patches/5.005_03 BitKeeper/deleted/.del-5.6.0~373be3a5ce47be85: Delete: bdb/perl.DB_File/patches/5.6.0 BitKeeper/deleted/.del-db-btree.t~3231595a1c241eb3: Delete: bdb/perl.DB_File/t/db-btree.t BitKeeper/deleted/.del-db-hash.t~7c4ad0c795c7fad2: Delete: bdb/perl.DB_File/t/db-hash.t BitKeeper/deleted/.del-db-recno.t~6c2d3d80b9ba4a50: Delete: bdb/perl.DB_File/t/db-recno.t BitKeeper/deleted/.del-db_server.sed~cdb00ebcd48a64e2: Delete: bdb/rpc_server/db_server.sed BitKeeper/deleted/.del-db_server_proc.c~d46c8f409c3747f4: Delete: bdb/rpc_server/db_server_proc.c BitKeeper/deleted/.del-db_server_svc.sed~3f5e59f334fa4607: Delete: bdb/rpc_server/db_server_svc.sed BitKeeper/deleted/.del-db_server_util.c~a809f3a4629acda: Delete: bdb/rpc_server/db_server_util.c BitKeeper/deleted/.del-log.tcl~ff1b41f1355b97d7: Delete: bdb/test/log.tcl BitKeeper/deleted/.del-mpool.tcl~b0df4dc1b04db26c: Delete: bdb/test/mpool.tcl BitKeeper/deleted/.del-mutex.tcl~52fd5c73a150565: Delete: bdb/test/mutex.tcl BitKeeper/deleted/.del-txn.tcl~c4ff071550b5446e: Delete: bdb/test/txn.tcl BitKeeper/deleted/.del-README~e800a12a5392010a: Delete: bdb/test/upgrade/README BitKeeper/deleted/.del-pack-2.6.6.pl~89d5076d758d3e98: Delete: bdb/test/upgrade/generate-2.X/pack-2.6.6.pl BitKeeper/deleted/.del-test-2.6.patch~4a52dc83d447547b: Delete: bdb/test/upgrade/generate-2.X/test-2.6.patch
1615 lines
36 KiB
C
1615 lines
36 KiB
C
/*-
|
|
* See the file LICENSE for redistribution information.
|
|
*
|
|
* Copyright (c) 1999-2002
|
|
* Sleepycat Software. All rights reserved.
|
|
*/
|
|
|
|
#include "db_config.h"
|
|
|
|
#ifndef lint
|
|
static const char revid[] = "$Id: qam.c,v 11.134 2002/08/13 20:46:08 ubell Exp $";
|
|
#endif /* not lint */
|
|
|
|
#ifndef NO_SYSTEM_INCLUDES
|
|
#include <sys/types.h>
|
|
|
|
#include <string.h>
|
|
#endif
|
|
|
|
#include "db_int.h"
|
|
#include "dbinc/db_page.h"
|
|
#include "dbinc/db_shash.h"
|
|
#include "dbinc/btree.h"
|
|
#include "dbinc/lock.h"
|
|
#include "dbinc/log.h"
|
|
#include "dbinc/qam.h"
|
|
|
|
static int __qam_bulk __P((DBC *, DBT *, u_int32_t));
|
|
static int __qam_c_close __P((DBC *, db_pgno_t, int *));
|
|
static int __qam_c_del __P((DBC *));
|
|
static int __qam_c_destroy __P((DBC *));
|
|
static int __qam_c_get __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *));
|
|
static int __qam_c_put __P((DBC *, DBT *, DBT *, u_int32_t, db_pgno_t *));
|
|
static int __qam_consume __P((DBC *, QMETA *, db_recno_t));
|
|
static int __qam_getno __P((DB *, const DBT *, db_recno_t *));
|
|
|
|
/*
|
|
* __qam_position --
|
|
* Position a queued access method cursor at a record. This returns
|
|
* the page locked. *exactp will be set if the record is valid.
|
|
* PUBLIC: int __qam_position
|
|
* PUBLIC: __P((DBC *, db_recno_t *, qam_position_mode, int *));
|
|
*/
|
|
int
|
|
__qam_position(dbc, recnop, mode, exactp)
|
|
DBC *dbc; /* open cursor */
|
|
db_recno_t *recnop; /* pointer to recno to find */
|
|
qam_position_mode mode;/* locking: read or write */
|
|
int *exactp; /* indicate if it was found */
|
|
{
|
|
QUEUE_CURSOR *cp;
|
|
DB *dbp;
|
|
QAMDATA *qp;
|
|
db_pgno_t pg;
|
|
int ret;
|
|
|
|
dbp = dbc->dbp;
|
|
cp = (QUEUE_CURSOR *)dbc->internal;
|
|
|
|
/* Fetch the page for this recno. */
|
|
pg = QAM_RECNO_PAGE(dbp, *recnop);
|
|
|
|
if ((ret = __db_lget(dbc, 0, pg, mode == QAM_READ ?
|
|
DB_LOCK_READ : DB_LOCK_WRITE, 0, &cp->lock)) != 0)
|
|
return (ret);
|
|
cp->page = NULL;
|
|
*exactp = 0;
|
|
if ((ret = __qam_fget(dbp, &pg,
|
|
mode == QAM_WRITE ? DB_MPOOL_CREATE : 0, &cp->page)) != 0) {
|
|
/* We did not fetch it, we can release the lock. */
|
|
(void)__LPUT(dbc, cp->lock);
|
|
if (mode != QAM_WRITE &&
|
|
(ret == DB_PAGE_NOTFOUND || ret == ENOENT))
|
|
return (0);
|
|
return (ret);
|
|
}
|
|
cp->pgno = pg;
|
|
cp->indx = QAM_RECNO_INDEX(dbp, pg, *recnop);
|
|
|
|
if (PGNO(cp->page) == 0) {
|
|
if (F_ISSET(dbp, DB_AM_RDONLY)) {
|
|
*exactp = 0;
|
|
return (0);
|
|
}
|
|
PGNO(cp->page) = pg;
|
|
TYPE(cp->page) = P_QAMDATA;
|
|
}
|
|
|
|
qp = QAM_GET_RECORD(dbp, cp->page, cp->indx);
|
|
*exactp = F_ISSET(qp, QAM_VALID) ? 1 : 0;
|
|
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* __qam_pitem --
|
|
* Put an item on a queue page. Copy the data to the page and set the
|
|
* VALID and SET bits. If logging and the record was previously set,
|
|
* log that data, otherwise just log the new data.
|
|
*
|
|
* pagep must be write locked
|
|
*
|
|
* PUBLIC: int __qam_pitem
|
|
* PUBLIC: __P((DBC *, QPAGE *, u_int32_t, db_recno_t, DBT *));
|
|
*/
|
|
int
|
|
__qam_pitem(dbc, pagep, indx, recno, data)
|
|
DBC *dbc;
|
|
QPAGE *pagep;
|
|
u_int32_t indx;
|
|
db_recno_t recno;
|
|
DBT *data;
|
|
{
|
|
DB *dbp;
|
|
DBT olddata, pdata, *datap;
|
|
QAMDATA *qp;
|
|
QUEUE *t;
|
|
u_int32_t alloced;
|
|
u_int8_t *dest, *p;
|
|
int ret;
|
|
|
|
alloced = ret = 0;
|
|
|
|
dbp = dbc->dbp;
|
|
t = (QUEUE *)dbp->q_internal;
|
|
|
|
if (data->size > t->re_len)
|
|
goto len_err;
|
|
|
|
qp = QAM_GET_RECORD(dbp, pagep, indx);
|
|
|
|
p = qp->data;
|
|
datap = data;
|
|
if (F_ISSET(data, DB_DBT_PARTIAL)) {
|
|
if (data->doff + data->dlen > t->re_len) {
|
|
alloced = data->dlen;
|
|
goto len_err;
|
|
}
|
|
if (data->size != data->dlen) {
|
|
len_err: __db_err(dbp->dbenv,
|
|
"Length improper for fixed length record %lu",
|
|
(u_long)(alloced ? alloced : data->size));
|
|
return (EINVAL);
|
|
}
|
|
if (data->size == t->re_len)
|
|
goto no_partial;
|
|
|
|
/*
|
|
* If we are logging, then we have to build the record
|
|
* first, otherwise, we can simply drop the change
|
|
* directly on the page. After this clause, make
|
|
* sure that datap and p are set up correctly so that
|
|
* copying datap into p does the right thing.
|
|
*
|
|
* Note, I am changing this so that if the existing
|
|
* record is not valid, we create a complete record
|
|
* to log so that both this and the recovery code is simpler.
|
|
*/
|
|
|
|
if (DBC_LOGGING(dbc) || !F_ISSET(qp, QAM_VALID)) {
|
|
datap = &pdata;
|
|
memset(datap, 0, sizeof(*datap));
|
|
|
|
if ((ret = __os_malloc(dbp->dbenv,
|
|
t->re_len, &datap->data)) != 0)
|
|
return (ret);
|
|
alloced = 1;
|
|
datap->size = t->re_len;
|
|
|
|
/*
|
|
* Construct the record if it's valid, otherwise set it
|
|
* all to the pad character.
|
|
*/
|
|
dest = datap->data;
|
|
if (F_ISSET(qp, QAM_VALID))
|
|
memcpy(dest, p, t->re_len);
|
|
else
|
|
memset(dest, t->re_pad, t->re_len);
|
|
|
|
dest += data->doff;
|
|
memcpy(dest, data->data, data->size);
|
|
} else {
|
|
datap = data;
|
|
p += data->doff;
|
|
}
|
|
}
|
|
|
|
no_partial:
|
|
if (DBC_LOGGING(dbc)) {
|
|
olddata.size = 0;
|
|
if (F_ISSET(qp, QAM_SET)) {
|
|
olddata.data = qp->data;
|
|
olddata.size = t->re_len;
|
|
}
|
|
if ((ret = __qam_add_log(dbp, dbc->txn, &LSN(pagep),
|
|
0, &LSN(pagep), pagep->pgno,
|
|
indx, recno, datap, qp->flags,
|
|
olddata.size == 0 ? NULL : &olddata)) != 0)
|
|
goto err;
|
|
}
|
|
|
|
F_SET(qp, QAM_VALID | QAM_SET);
|
|
memcpy(p, datap->data, datap->size);
|
|
if (!F_ISSET(data, DB_DBT_PARTIAL))
|
|
memset(p + datap->size, t->re_pad, t->re_len - datap->size);
|
|
|
|
err: if (alloced)
|
|
__os_free(dbp->dbenv, datap->data);
|
|
|
|
return (ret);
|
|
}
|
|
/*
|
|
* __qam_c_put
|
|
* Cursor put for queued access method.
|
|
* BEFORE and AFTER cannot be specified.
|
|
*/
|
|
static int
|
|
__qam_c_put(dbc, key, data, flags, pgnop)
|
|
DBC *dbc;
|
|
DBT *key, *data;
|
|
u_int32_t flags;
|
|
db_pgno_t *pgnop;
|
|
{
|
|
DB *dbp;
|
|
DB_LOCK lock;
|
|
DB_MPOOLFILE *mpf;
|
|
QMETA *meta;
|
|
QUEUE_CURSOR *cp;
|
|
db_pgno_t pg;
|
|
db_recno_t new_cur, new_first;
|
|
u_int32_t opcode;
|
|
int exact, ret, t_ret;
|
|
|
|
dbp = dbc->dbp;
|
|
mpf = dbp->mpf;
|
|
if (pgnop != NULL)
|
|
*pgnop = PGNO_INVALID;
|
|
|
|
cp = (QUEUE_CURSOR *)dbc->internal;
|
|
|
|
switch (flags) {
|
|
case DB_KEYFIRST:
|
|
case DB_KEYLAST:
|
|
if ((ret = __qam_getno(dbp, key, &cp->recno)) != 0)
|
|
return (ret);
|
|
/* FALLTHROUGH */
|
|
case DB_CURRENT:
|
|
break;
|
|
default:
|
|
/* The interface shouldn't let anything else through. */
|
|
DB_ASSERT(0);
|
|
return (__db_ferr(dbp->dbenv, "__qam_c_put", flags));
|
|
}
|
|
|
|
/* Write lock the record. */
|
|
if ((ret = __db_lget(dbc,
|
|
0, cp->recno, DB_LOCK_WRITE, DB_LOCK_RECORD, &lock)) != 0)
|
|
return (ret);
|
|
|
|
if ((ret = __qam_position(dbc,
|
|
&cp->recno, QAM_WRITE, &exact)) != 0) {
|
|
/* We could not get the page, we can release the record lock. */
|
|
__LPUT(dbc, lock);
|
|
return (ret);
|
|
}
|
|
|
|
/* Put the item on the page. */
|
|
ret = __qam_pitem(dbc, (QPAGE *)cp->page, cp->indx, cp->recno, data);
|
|
|
|
/* Doing record locking, release the page lock */
|
|
if ((t_ret = __LPUT(dbc, cp->lock)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
if ((t_ret = __qam_fput(
|
|
dbp, cp->pgno, cp->page, DB_MPOOL_DIRTY)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
cp->page = NULL;
|
|
cp->lock = lock;
|
|
cp->lock_mode = DB_LOCK_WRITE;
|
|
if (ret != 0)
|
|
return (ret);
|
|
|
|
/* We may need to reset the head or tail of the queue. */
|
|
pg = ((QUEUE *)dbp->q_internal)->q_meta;
|
|
|
|
/*
|
|
* Get the meta page first, we don't want to write lock it while
|
|
* trying to pin it.
|
|
*/
|
|
if ((ret = mpf->get(mpf, &pg, 0, &meta)) != 0)
|
|
return (ret);
|
|
if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_WRITE, 0, &lock)) != 0) {
|
|
(void)mpf->put(mpf, meta, 0);
|
|
return (ret);
|
|
}
|
|
|
|
opcode = 0;
|
|
new_cur = new_first = 0;
|
|
|
|
/*
|
|
* If the put address is outside the queue, adjust the head and
|
|
* tail of the queue. If the order is inverted we move
|
|
* the one which is closer. The first case is when the
|
|
* queue is empty, move first and current to where the new
|
|
* insert is.
|
|
*/
|
|
|
|
if (meta->first_recno == meta->cur_recno) {
|
|
new_first = cp->recno;
|
|
new_cur = cp->recno + 1;
|
|
if (new_cur == RECNO_OOB)
|
|
new_cur++;
|
|
opcode |= QAM_SETFIRST;
|
|
opcode |= QAM_SETCUR;
|
|
} else {
|
|
if (QAM_BEFORE_FIRST(meta, cp->recno) &&
|
|
(meta->first_recno <= meta->cur_recno ||
|
|
meta->first_recno - cp->recno <
|
|
cp->recno - meta->cur_recno)) {
|
|
new_first = cp->recno;
|
|
opcode |= QAM_SETFIRST;
|
|
}
|
|
|
|
if (meta->cur_recno == cp->recno ||
|
|
(QAM_AFTER_CURRENT(meta, cp->recno) &&
|
|
(meta->first_recno <= meta->cur_recno ||
|
|
cp->recno - meta->cur_recno <=
|
|
meta->first_recno - cp->recno))) {
|
|
new_cur = cp->recno + 1;
|
|
if (new_cur == RECNO_OOB)
|
|
new_cur++;
|
|
opcode |= QAM_SETCUR;
|
|
}
|
|
}
|
|
|
|
if (opcode != 0 && DBC_LOGGING(dbc)) {
|
|
ret = __qam_mvptr_log(dbp, dbc->txn, &meta->dbmeta.lsn,
|
|
0, opcode, meta->first_recno, new_first,
|
|
meta->cur_recno, new_cur, &meta->dbmeta.lsn, PGNO_BASE_MD);
|
|
if (ret != 0)
|
|
opcode = 0;
|
|
}
|
|
|
|
if (opcode & QAM_SETCUR)
|
|
meta->cur_recno = new_cur;
|
|
if (opcode & QAM_SETFIRST)
|
|
meta->first_recno = new_first;
|
|
|
|
if ((t_ret = mpf->put(
|
|
mpf, meta, opcode != 0 ? DB_MPOOL_DIRTY : 0)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
|
|
/* Don't hold the meta page long term. */
|
|
if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* __qam_append --
|
|
* Perform a put(DB_APPEND) in queue.
|
|
*
|
|
* PUBLIC: int __qam_append __P((DBC *, DBT *, DBT *));
|
|
*/
|
|
int
|
|
__qam_append(dbc, key, data)
|
|
DBC *dbc;
|
|
DBT *key, *data;
|
|
{
|
|
DB *dbp;
|
|
DB_LOCK lock;
|
|
DB_MPOOLFILE *mpf;
|
|
QMETA *meta;
|
|
QPAGE *page;
|
|
QUEUE *qp;
|
|
QUEUE_CURSOR *cp;
|
|
db_pgno_t pg;
|
|
db_recno_t recno;
|
|
int ret, t_ret;
|
|
|
|
dbp = dbc->dbp;
|
|
mpf = dbp->mpf;
|
|
cp = (QUEUE_CURSOR *)dbc->internal;
|
|
|
|
pg = ((QUEUE *)dbp->q_internal)->q_meta;
|
|
/*
|
|
* Get the meta page first, we don't want to write lock it while
|
|
* trying to pin it.
|
|
*/
|
|
if ((ret = mpf->get(mpf, &pg, 0, &meta)) != 0)
|
|
return (ret);
|
|
/* Write lock the meta page. */
|
|
if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_WRITE, 0, &lock)) != 0) {
|
|
(void)mpf->put(mpf, meta, 0);
|
|
return (ret);
|
|
}
|
|
|
|
/* Get the next record number. */
|
|
recno = meta->cur_recno;
|
|
meta->cur_recno++;
|
|
if (meta->cur_recno == RECNO_OOB)
|
|
meta->cur_recno++;
|
|
if (meta->cur_recno == meta->first_recno) {
|
|
meta->cur_recno--;
|
|
if (meta->cur_recno == RECNO_OOB)
|
|
meta->cur_recno--;
|
|
(void)__LPUT(dbc, lock);
|
|
ret = EFBIG;
|
|
goto err;
|
|
}
|
|
|
|
if (QAM_BEFORE_FIRST(meta, recno))
|
|
meta->first_recno = recno;
|
|
|
|
/* Lock the record and release meta page lock. */
|
|
if ((ret = __db_lget(dbc, LCK_COUPLE_ALWAYS,
|
|
recno, DB_LOCK_WRITE, DB_LOCK_RECORD, &lock)) != 0) {
|
|
(void)__LPUT(dbc, lock);
|
|
goto err;
|
|
}
|
|
|
|
/*
|
|
* The application may modify the data based on the selected record
|
|
* number.
|
|
*/
|
|
if (dbc->dbp->db_append_recno != NULL &&
|
|
(ret = dbc->dbp->db_append_recno(dbc->dbp, data, recno)) != 0) {
|
|
(void)__LPUT(dbc, lock);
|
|
goto err;
|
|
}
|
|
|
|
cp->lock = lock;
|
|
cp->lock_mode = DB_LOCK_WRITE;
|
|
|
|
pg = QAM_RECNO_PAGE(dbp, recno);
|
|
|
|
/* Fetch and write lock the data page. */
|
|
if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_WRITE, 0, &lock)) != 0)
|
|
goto err;
|
|
if ((ret = __qam_fget(dbp, &pg, DB_MPOOL_CREATE, &page)) != 0) {
|
|
/* We did not fetch it, we can release the lock. */
|
|
(void)__LPUT(dbc, lock);
|
|
goto err;
|
|
}
|
|
|
|
/* See if this is a new page. */
|
|
if (page->pgno == 0) {
|
|
page->pgno = pg;
|
|
page->type = P_QAMDATA;
|
|
}
|
|
|
|
/* Put the item on the page and log it. */
|
|
ret = __qam_pitem(dbc, page,
|
|
QAM_RECNO_INDEX(dbp, pg, recno), recno, data);
|
|
|
|
/* Doing record locking, release the page lock */
|
|
if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
|
|
if ((t_ret
|
|
= __qam_fput(dbp, pg, page, DB_MPOOL_DIRTY)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
|
|
/* Return the record number to the user. */
|
|
if (ret == 0)
|
|
ret = __db_retcopy(dbp->dbenv, key,
|
|
&recno, sizeof(recno), &dbc->rkey->data, &dbc->rkey->ulen);
|
|
|
|
/* Position the cursor on this record. */
|
|
cp->recno = recno;
|
|
|
|
/* See if we are leaving the extent. */
|
|
qp = (QUEUE *) dbp->q_internal;
|
|
if (qp->page_ext != 0 &&
|
|
(recno % (qp->page_ext * qp->rec_page) == 0 ||
|
|
recno == UINT32_T_MAX)) {
|
|
if ((ret = __db_lget(dbc,
|
|
0, ((QUEUE *)dbp->q_internal)->q_meta,
|
|
DB_LOCK_WRITE, 0, &lock)) != 0)
|
|
goto err;
|
|
if (!QAM_AFTER_CURRENT(meta, recno))
|
|
ret = __qam_fclose(dbp, pg);
|
|
(void)__LPUT(dbc, lock);
|
|
}
|
|
|
|
err:
|
|
/* Release the meta page. */
|
|
if ((t_ret = mpf->put(mpf, meta, DB_MPOOL_DIRTY)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* __qam_c_del --
|
|
* Qam cursor->am_del function
|
|
*/
|
|
static int
|
|
__qam_c_del(dbc)
|
|
DBC *dbc;
|
|
{
|
|
DB *dbp;
|
|
DBT data;
|
|
DB_LOCK lock;
|
|
DB_MPOOLFILE *mpf;
|
|
PAGE *pagep;
|
|
QAMDATA *qp;
|
|
QMETA *meta;
|
|
QUEUE_CURSOR *cp;
|
|
db_pgno_t pg;
|
|
db_recno_t first;
|
|
int exact, ret, t_ret;
|
|
|
|
dbp = dbc->dbp;
|
|
mpf = dbp->mpf;
|
|
cp = (QUEUE_CURSOR *)dbc->internal;
|
|
|
|
pg = ((QUEUE *)dbp->q_internal)->q_meta;
|
|
/*
|
|
* Get the meta page first, we don't want to write lock it while
|
|
* trying to pin it.
|
|
*/
|
|
if ((ret = mpf->get(mpf, &pg, 0, &meta)) != 0)
|
|
return (ret);
|
|
/* Write lock the meta page. */
|
|
if ((ret = __db_lget(dbc, 0, pg, DB_LOCK_READ, 0, &lock)) != 0) {
|
|
(void)mpf->put(mpf, meta, 0);
|
|
return (ret);
|
|
}
|
|
|
|
if (QAM_NOT_VALID(meta, cp->recno))
|
|
ret = DB_NOTFOUND;
|
|
|
|
first = meta->first_recno;
|
|
|
|
/* Don't hold the meta page long term. */
|
|
if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
|
|
if (ret != 0)
|
|
goto err1;
|
|
|
|
if ((ret = __db_lget(dbc,
|
|
0, cp->recno, DB_LOCK_WRITE, DB_LOCK_RECORD, &lock)) != 0)
|
|
goto err1;
|
|
|
|
cp->lock_mode = DB_LOCK_WRITE;
|
|
/* Find the record ; delete only deletes exact matches. */
|
|
if ((ret = __qam_position(dbc,
|
|
&cp->recno, QAM_WRITE, &exact)) != 0) {
|
|
cp->lock = lock;
|
|
goto err1;
|
|
}
|
|
if (!exact) {
|
|
ret = DB_NOTFOUND;
|
|
goto err1;
|
|
}
|
|
|
|
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 err1;
|
|
} 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 err1;
|
|
}
|
|
}
|
|
|
|
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, &lock)) != 0)
|
|
goto err1;
|
|
ret = __qam_consume(dbc, meta, first);
|
|
if ((t_ret = __LPUT(dbc, lock)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
}
|
|
|
|
err1:
|
|
if ((t_ret = mpf->put(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, is_first, locked, ret, t_ret, wait, with_delete;
|
|
int put_mode, meta_dirty, 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;
|
|
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) {
|
|
if ((ret = __db_check_txn(dbp, dbc->txn, dbc->locker, 0)) != 0)
|
|
return (ret);
|
|
|
|
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. */
|
|
meta_dirty = 0;
|
|
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 = mpf->get(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. */
|
|
(void)__TLPUT(dbc, cp->lock);
|
|
|
|
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:
|
|
if (cp->recno != RECNO_OOB) {
|
|
++cp->recno;
|
|
/* Wrap around, skipping zero. */
|
|
if (cp->recno == RECNO_OOB)
|
|
cp->recno++;
|
|
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 (QAM_BEFORE_FIRST(meta, cp->recno) ||
|
|
cp->recno == meta->first_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;
|
|
break;
|
|
default:
|
|
ret = __db_unknown_flag(dbenv, "__qam_c_get", flags);
|
|
goto err;
|
|
}
|
|
|
|
/*
|
|
* Check to see if we are out of data. Current points to
|
|
* the first free slot.
|
|
*/
|
|
if (cp->recno == meta->cur_recno ||
|
|
QAM_AFTER_CURRENT(meta, cp->recno)) {
|
|
ret = DB_NOTFOUND;
|
|
pg = NULL;
|
|
if (wait) {
|
|
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)) {
|
|
if ((ret = dbenv->lock_get(
|
|
dbenv, dbc->locker,
|
|
DB_LOCK_SWITCH, &dbc->lock_dbt,
|
|
DB_LOCK_WAIT, &dbc->mylock)) != 0)
|
|
goto err;
|
|
if ((ret = dbenv->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 != RECNO_OOB &&
|
|
!QAM_AFTER_CURRENT(meta, cp->recno))
|
|
goto retry;
|
|
}
|
|
if ((ret = __db_lget(dbc, 0, metapno,
|
|
DB_LOCK_WAIT, DB_LOCK_SWITCH, &metalock)) != 0)
|
|
goto err;
|
|
if ((ret = dbenv->lock_get(dbenv, dbc->locker,
|
|
DB_LOCK_UPGRADE, &dbc->lock_dbt, DB_LOCK_WRITE,
|
|
&metalock)) != 0)
|
|
goto err;
|
|
locked = 1;
|
|
goto retry;
|
|
}
|
|
|
|
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_NOTGRANTED && 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 ((!with_delete && is_first) || flags == DB_LAST) {
|
|
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))) {
|
|
__LPUT(dbc, lock);
|
|
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) {
|
|
if (flags == DB_NEXT || flags == DB_NEXT_NODUP ||
|
|
flags == DB_PREV || flags == DB_PREV_NODUP ||
|
|
flags == DB_LAST) {
|
|
/* Release locks and try again. */
|
|
if (pg != NULL)
|
|
(void)__qam_fput(dbp, cp->pgno, pg, 0);
|
|
cp->page = pg = NULL;
|
|
(void)__LPUT(dbc, pglock);
|
|
(void)__LPUT(dbc, cp->lock);
|
|
if (flags == DB_LAST)
|
|
flags = DB_PREV;
|
|
if (!with_delete)
|
|
is_first = 0;
|
|
retrying = 0;
|
|
goto retry;
|
|
}
|
|
/* this is for the SET and SET_RANGE cases */
|
|
ret = DB_KEYEMPTY;
|
|
goto err1;
|
|
}
|
|
|
|
/* Return the key if the user didn't give us one. */
|
|
if (key != NULL) {
|
|
if (flags != DB_GET_BOTH && flags != DB_GET_BOTH_RANGE &&
|
|
flags != DB_SET && flags != DB_SET_RANGE &&
|
|
(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);
|
|
}
|
|
|
|
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) {
|
|
ret = DB_NOTFOUND;
|
|
goto err1;
|
|
}
|
|
}
|
|
if (data != NULL &&
|
|
!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;
|
|
|
|
if (data != NULL)
|
|
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_POSITIONI)) != 0)
|
|
goto err1;
|
|
|
|
if ((ret = __db_c_del_primary(dbcdup)) != 0) {
|
|
/*
|
|
* The __db_c_del_primary return is more
|
|
* interesting.
|
|
*/
|
|
(void)dbcdup->c_close(dbcdup);
|
|
goto err1;
|
|
}
|
|
|
|
if ((ret = dbcdup->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) {
|
|
t_ret = __qam_fput(dbp, cp->pgno, cp->page, put_mode);
|
|
|
|
if (!ret)
|
|
ret = t_ret;
|
|
/* Doing record locking, release the page lock */
|
|
t_ret = __LPUT(dbc, pglock);
|
|
cp->page = NULL;
|
|
}
|
|
|
|
err: if (!ret)
|
|
ret = t_ret;
|
|
if (meta) {
|
|
|
|
/* release the meta page */
|
|
t_ret = mpf->put(mpf, meta, meta_dirty ? DB_MPOOL_DIRTY : 0);
|
|
|
|
if (!ret)
|
|
ret = t_ret;
|
|
|
|
/* Don't hold the meta page long term. */
|
|
if (locked)
|
|
t_ret = __LPUT(dbc, metalock);
|
|
}
|
|
DB_ASSERT(!LOCK_ISSET(metalock));
|
|
|
|
/*
|
|
* There is no need to keep the record locked if we are
|
|
* not in a transaction.
|
|
*/
|
|
if (t_ret == 0)
|
|
t_ret = __TLPUT(dbc, cp->lock);
|
|
|
|
return (ret ? ret : t_ret);
|
|
}
|
|
|
|
/*
|
|
* __qam_consume -- try to reset the head of the queue.
|
|
*
|
|
*/
|
|
|
|
static int
|
|
__qam_consume(dbc, meta, first)
|
|
DBC *dbc;
|
|
QMETA *meta;
|
|
db_recno_t first;
|
|
{
|
|
DB *dbp;
|
|
DB_LOCK lock, save_lock;
|
|
DB_MPOOLFILE *mpf;
|
|
QUEUE_CURSOR *cp;
|
|
db_indx_t save_indx;
|
|
db_pgno_t save_page;
|
|
db_recno_t current, save_recno;
|
|
u_int32_t rec_extent;
|
|
int exact, put_mode, ret, t_ret, wrapped;
|
|
|
|
dbp = dbc->dbp;
|
|
mpf = dbp->mpf;
|
|
cp = (QUEUE_CURSOR *)dbc->internal;
|
|
put_mode = DB_MPOOL_DIRTY;
|
|
ret = t_ret = 0;
|
|
|
|
save_page = cp->pgno;
|
|
save_indx = cp->indx;
|
|
save_recno = cp->recno;
|
|
save_lock = cp->lock;
|
|
|
|
/*
|
|
* If we skipped some deleted records, we need to
|
|
* reposition on the first one. Get a lock
|
|
* in case someone is trying to put it back.
|
|
*/
|
|
if (first != cp->recno) {
|
|
ret = __db_lget(dbc, 0, first, DB_LOCK_READ,
|
|
DB_LOCK_NOWAIT | DB_LOCK_RECORD, &lock);
|
|
if (ret == DB_LOCK_NOTGRANTED) {
|
|
ret = 0;
|
|
goto done;
|
|
}
|
|
if (ret != 0)
|
|
goto done;
|
|
if ((ret =
|
|
__qam_fput(dbp, cp->pgno, cp->page, put_mode)) != 0)
|
|
goto done;
|
|
cp->page = NULL;
|
|
put_mode = 0;
|
|
if ((ret = __qam_position(dbc,
|
|
&first, QAM_READ, &exact)) != 0 || exact != 0) {
|
|
(void)__LPUT(dbc, lock);
|
|
goto done;
|
|
}
|
|
if ((ret =__LPUT(dbc, lock)) != 0)
|
|
goto done;
|
|
if ((ret = __LPUT(dbc, cp->lock)) != 0)
|
|
goto done;
|
|
}
|
|
|
|
current = meta->cur_recno;
|
|
wrapped = 0;
|
|
if (first > current)
|
|
wrapped = 1;
|
|
rec_extent = meta->page_ext * meta->rec_page;
|
|
|
|
/* Loop until we find a record or hit current */
|
|
for (;;) {
|
|
/*
|
|
* Check to see if we are moving off the extent
|
|
* and remove the extent.
|
|
* If we are moving off a page we need to
|
|
* get rid of the buffer.
|
|
* Wait for the lagging readers to move off the
|
|
* page.
|
|
*/
|
|
if (cp->page != NULL && rec_extent != 0 &&
|
|
((exact = (first % rec_extent == 0)) ||
|
|
first % meta->rec_page == 0 ||
|
|
first == UINT32_T_MAX)) {
|
|
if (exact == 1 && (ret = __db_lget(dbc,
|
|
0, cp->pgno, DB_LOCK_WRITE, 0, &cp->lock)) != 0)
|
|
break;
|
|
|
|
#ifdef QDEBUG
|
|
__db_logmsg(dbp->dbenv,
|
|
dbc->txn, "Queue R", 0, "%x %d %d %d",
|
|
dbc->locker, cp->pgno, first, meta->first_recno);
|
|
#endif
|
|
put_mode |= DB_MPOOL_DISCARD;
|
|
if ((ret = __qam_fput(dbp,
|
|
cp->pgno, cp->page, put_mode)) != 0)
|
|
break;
|
|
cp->page = NULL;
|
|
|
|
if (exact == 1) {
|
|
ret = __qam_fremove(dbp, cp->pgno);
|
|
t_ret = __LPUT(dbc, cp->lock);
|
|
}
|
|
if (ret != 0)
|
|
break;
|
|
if (t_ret != 0) {
|
|
ret = t_ret;
|
|
break;
|
|
}
|
|
} else if (cp->page != NULL && (ret =
|
|
__qam_fput(dbp, cp->pgno, cp->page, put_mode)) != 0)
|
|
break;
|
|
cp->page = NULL;
|
|
first++;
|
|
if (first == RECNO_OOB) {
|
|
wrapped = 0;
|
|
first++;
|
|
}
|
|
|
|
/*
|
|
* LOOP EXIT when we come move to the current
|
|
* pointer.
|
|
*/
|
|
if (!wrapped && first >= current)
|
|
break;
|
|
|
|
ret = __db_lget(dbc, 0, first, DB_LOCK_READ,
|
|
DB_LOCK_NOWAIT | DB_LOCK_RECORD, &lock);
|
|
if (ret == DB_LOCK_NOTGRANTED) {
|
|
ret = 0;
|
|
break;
|
|
}
|
|
if (ret != 0)
|
|
break;
|
|
|
|
if ((ret = __qam_position(dbc,
|
|
&first, QAM_READ, &exact)) != 0) {
|
|
(void)__LPUT(dbc, lock);
|
|
break;
|
|
}
|
|
put_mode = 0;
|
|
if ((ret =__LPUT(dbc, lock)) != 0 ||
|
|
(ret = __LPUT(dbc, cp->lock)) != 0 || exact) {
|
|
if ((t_ret = __qam_fput(dbp, cp->pgno,
|
|
cp->page, put_mode)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
cp->page = NULL;
|
|
break;
|
|
}
|
|
}
|
|
|
|
cp->pgno = save_page;
|
|
cp->indx = save_indx;
|
|
cp->recno = save_recno;
|
|
cp->lock = save_lock;
|
|
|
|
/*
|
|
* We have advanced as far as we can.
|
|
* Advance first_recno to this point.
|
|
*/
|
|
if (ret == 0 && meta->first_recno != first) {
|
|
#ifdef QDEBUG
|
|
__db_logmsg(dbp->dbenv, dbc->txn, "Queue M",
|
|
0, "%x %d %d %d", dbc->locker, cp->recno,
|
|
first, meta->first_recno);
|
|
#endif
|
|
if (DBC_LOGGING(dbc))
|
|
if ((ret = __qam_incfirst_log(dbp,
|
|
dbc->txn, &meta->dbmeta.lsn, 0,
|
|
cp->recno, PGNO_BASE_MD)) != 0)
|
|
goto done;
|
|
meta->first_recno = first;
|
|
(void)mpf->set(mpf, meta, DB_MPOOL_DIRTY);
|
|
}
|
|
|
|
done:
|
|
return (ret);
|
|
}
|
|
|
|
static int
|
|
__qam_bulk(dbc, data, flags)
|
|
DBC *dbc;
|
|
DBT *data;
|
|
u_int32_t flags;
|
|
{
|
|
DB *dbp;
|
|
DB_LOCK metalock;
|
|
DB_MPOOLFILE *mpf;
|
|
PAGE *pg;
|
|
QMETA *meta;
|
|
QAMDATA *qp;
|
|
QUEUE_CURSOR *cp;
|
|
db_indx_t indx;
|
|
db_pgno_t metapno;
|
|
qam_position_mode mode;
|
|
int32_t *endp, *offp;
|
|
u_int8_t *dbuf, *dp, *np;
|
|
int exact, recs, re_len, ret, t_ret, valid;
|
|
int is_key, need_pg, pagesize, size, space;
|
|
|
|
dbp = dbc->dbp;
|
|
mpf = dbp->mpf;
|
|
cp = (QUEUE_CURSOR *)dbc->internal;
|
|
|
|
mode = QAM_READ;
|
|
if (F_ISSET(dbc, DBC_RMW))
|
|
mode = QAM_WRITE;
|
|
|
|
pagesize = dbp->pgsize;
|
|
re_len = ((QUEUE *)dbp->q_internal)->re_len;
|
|
recs = ((QUEUE *)dbp->q_internal)->rec_page;
|
|
metapno = ((QUEUE *)dbp->q_internal)->q_meta;
|
|
|
|
is_key = LF_ISSET(DB_MULTIPLE_KEY) ? 1 : 0;
|
|
size = 0;
|
|
|
|
if ((ret = __db_lget(dbc, 0, metapno, DB_LOCK_READ, 0, &metalock)) != 0)
|
|
return (ret);
|
|
if ((ret = mpf->get(mpf, &metapno, 0, &meta)) != 0) {
|
|
/* We did not fetch it, we can release the lock. */
|
|
(void)__LPUT(dbc, metalock);
|
|
return (ret);
|
|
}
|
|
|
|
dbuf = data->data;
|
|
np = dp = dbuf;
|
|
|
|
/* Keep track of space that is left. There is an termination entry */
|
|
space = data->ulen;
|
|
space -= sizeof(*offp);
|
|
|
|
/* Build the offset/size table form the end up. */
|
|
endp = (int32_t *) ((u_int8_t *)dbuf + data->ulen);
|
|
endp--;
|
|
offp = endp;
|
|
|
|
next_pg:
|
|
if ((ret = __qam_position(dbc, &cp->recno, mode, &exact)) != 0)
|
|
goto done;
|
|
|
|
pg = cp->page;
|
|
indx = cp->indx;
|
|
need_pg = 1;
|
|
|
|
do {
|
|
/*
|
|
* If this page is a nonexistent page at the end of an
|
|
* extent, pg may be NULL. A NULL page has no valid records,
|
|
* so just keep looping as though qp exists and isn't QAM_VALID;
|
|
* calling QAM_GET_RECORD is unsafe.
|
|
*/
|
|
valid = 0;
|
|
|
|
/* Wrap around, skipping zero. */
|
|
if (cp->recno == RECNO_OOB)
|
|
cp->recno++;
|
|
if (pg != NULL) {
|
|
qp = QAM_GET_RECORD(dbp, pg, indx);
|
|
if (F_ISSET(qp, QAM_VALID)) {
|
|
valid = 1;
|
|
space -= (is_key ? 3 : 2) * sizeof(*offp);
|
|
if (space < 0)
|
|
goto get_space;
|
|
if (need_pg) {
|
|
dp = np;
|
|
size = pagesize - QPAGE_SZ(dbp);
|
|
if (space < size) {
|
|
get_space:
|
|
if (offp == endp) {
|
|
data->size =
|
|
ALIGN(size +
|
|
pagesize,
|
|
sizeof(u_int32_t));
|
|
ret = ENOMEM;
|
|
break;
|
|
}
|
|
if (indx != 0)
|
|
indx--;
|
|
cp->recno--;
|
|
break;
|
|
}
|
|
memcpy(dp,
|
|
(char *)pg + QPAGE_SZ(dbp), size);
|
|
need_pg = 0;
|
|
space -= size;
|
|
np += size;
|
|
}
|
|
if (is_key)
|
|
*offp-- = cp->recno;
|
|
*offp-- = (int32_t)((u_int8_t*)qp -
|
|
(u_int8_t*)pg - QPAGE_SZ(dbp) +
|
|
dp - dbuf + SSZA(QAMDATA, data));
|
|
*offp-- = re_len;
|
|
}
|
|
}
|
|
if (!valid && is_key == 0) {
|
|
*offp-- = 0;
|
|
*offp-- = 0;
|
|
}
|
|
cp->recno++;
|
|
} while (++indx < recs && indx != RECNO_OOB
|
|
&& cp->recno != meta->cur_recno
|
|
&& !QAM_AFTER_CURRENT(meta, cp->recno));
|
|
|
|
if ((t_ret = __TLPUT(dbc, cp->lock)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
|
|
if (cp->page != NULL) {
|
|
if ((t_ret =
|
|
__qam_fput(dbp, cp->pgno, cp->page, 0)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
cp->page = NULL;
|
|
}
|
|
|
|
if (ret == 0
|
|
&& (indx >= recs || indx == RECNO_OOB)
|
|
&& cp->recno != meta->cur_recno
|
|
&& !QAM_AFTER_CURRENT(meta, cp->recno))
|
|
goto next_pg;
|
|
|
|
if (is_key == 1)
|
|
*offp = RECNO_OOB;
|
|
else
|
|
*offp = -1;
|
|
|
|
done:
|
|
/* release the meta page */
|
|
t_ret = mpf->put(mpf, meta, 0);
|
|
|
|
if (!ret)
|
|
ret = t_ret;
|
|
|
|
t_ret = __LPUT(dbc, metalock);
|
|
|
|
return (ret);
|
|
}
|
|
|
|
/*
|
|
* __qam_c_close --
|
|
* Close down the cursor from a single use.
|
|
*/
|
|
static int
|
|
__qam_c_close(dbc, root_pgno, rmroot)
|
|
DBC *dbc;
|
|
db_pgno_t root_pgno;
|
|
int *rmroot;
|
|
{
|
|
QUEUE_CURSOR *cp;
|
|
|
|
COMPQUIET(root_pgno, 0);
|
|
COMPQUIET(rmroot, NULL);
|
|
|
|
cp = (QUEUE_CURSOR *)dbc->internal;
|
|
|
|
/* Discard any locks not acquired inside of a transaction. */
|
|
(void)__TLPUT(dbc, cp->lock);
|
|
LOCK_INIT(cp->lock);
|
|
|
|
cp->page = NULL;
|
|
cp->pgno = PGNO_INVALID;
|
|
cp->indx = 0;
|
|
cp->lock_mode = DB_LOCK_NG;
|
|
cp->recno = RECNO_OOB;
|
|
cp->flags = 0;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* __qam_c_dup --
|
|
* Duplicate a queue cursor, such that the new one holds appropriate
|
|
* locks for the position of the original.
|
|
*
|
|
* PUBLIC: int __qam_c_dup __P((DBC *, DBC *));
|
|
*/
|
|
int
|
|
__qam_c_dup(orig_dbc, new_dbc)
|
|
DBC *orig_dbc, *new_dbc;
|
|
{
|
|
QUEUE_CURSOR *orig, *new;
|
|
|
|
orig = (QUEUE_CURSOR *)orig_dbc->internal;
|
|
new = (QUEUE_CURSOR *)new_dbc->internal;
|
|
|
|
new->recno = orig->recno;
|
|
|
|
/* reget the long term lock if we are not in a xact */
|
|
if (orig_dbc->txn != NULL ||
|
|
!STD_LOCKING(orig_dbc) || !LOCK_ISSET(orig->lock))
|
|
return (0);
|
|
|
|
return (__db_lget(new_dbc,
|
|
0, new->recno, new->lock_mode, DB_LOCK_RECORD, &new->lock));
|
|
}
|
|
|
|
/*
|
|
* __qam_c_init
|
|
*
|
|
* PUBLIC: int __qam_c_init __P((DBC *));
|
|
*/
|
|
int
|
|
__qam_c_init(dbc)
|
|
DBC *dbc;
|
|
{
|
|
QUEUE_CURSOR *cp;
|
|
DB *dbp;
|
|
int ret;
|
|
|
|
dbp = dbc->dbp;
|
|
|
|
/* Allocate the internal structure. */
|
|
cp = (QUEUE_CURSOR *)dbc->internal;
|
|
if (cp == NULL) {
|
|
if ((ret =
|
|
__os_calloc(dbp->dbenv, 1, sizeof(QUEUE_CURSOR), &cp)) != 0)
|
|
return (ret);
|
|
dbc->internal = (DBC_INTERNAL *)cp;
|
|
}
|
|
|
|
/* Initialize methods. */
|
|
dbc->c_close = __db_c_close;
|
|
dbc->c_count = __db_c_count;
|
|
dbc->c_del = __db_c_del;
|
|
dbc->c_dup = __db_c_dup;
|
|
dbc->c_get = dbc->c_real_get = __db_c_get;
|
|
dbc->c_pget = __db_c_pget;
|
|
dbc->c_put = __db_c_put;
|
|
dbc->c_am_bulk = __qam_bulk;
|
|
dbc->c_am_close = __qam_c_close;
|
|
dbc->c_am_del = __qam_c_del;
|
|
dbc->c_am_destroy = __qam_c_destroy;
|
|
dbc->c_am_get = __qam_c_get;
|
|
dbc->c_am_put = __qam_c_put;
|
|
dbc->c_am_writelock = NULL;
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* __qam_c_destroy --
|
|
* Close a single cursor -- internal version.
|
|
*/
|
|
static int
|
|
__qam_c_destroy(dbc)
|
|
DBC *dbc;
|
|
{
|
|
/* Discard the structures. */
|
|
__os_free(dbc->dbp->dbenv, dbc->internal);
|
|
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* __qam_getno --
|
|
* Check the user's record number.
|
|
*/
|
|
static int
|
|
__qam_getno(dbp, key, rep)
|
|
DB *dbp;
|
|
const DBT *key;
|
|
db_recno_t *rep;
|
|
{
|
|
if ((*rep = *(db_recno_t *)key->data) == 0) {
|
|
__db_err(dbp->dbenv, "illegal record number of 0");
|
|
return (EINVAL);
|
|
}
|
|
return (0);
|
|
}
|
|
|
|
/*
|
|
* __qam_truncate --
|
|
* Truncate a queue database
|
|
*
|
|
* PUBLIC: int __qam_truncate __P((DB *, DB_TXN *, u_int32_t *));
|
|
*/
|
|
int
|
|
__qam_truncate(dbp, txn, countp)
|
|
DB *dbp;
|
|
DB_TXN *txn;
|
|
u_int32_t *countp;
|
|
{
|
|
DBC *dbc;
|
|
DB_LOCK metalock;
|
|
DB_MPOOLFILE *mpf;
|
|
QMETA *meta;
|
|
db_pgno_t metapno;
|
|
int count, ret, t_ret;
|
|
|
|
mpf = dbp->mpf;
|
|
|
|
/* Acquire a cursor. */
|
|
if ((ret = dbp->cursor(dbp, txn, &dbc, 0)) != 0)
|
|
return (ret);
|
|
|
|
/* Walk the queue, counting rows. */
|
|
count = 0;
|
|
while ((ret = __qam_c_get(dbc, NULL, NULL, DB_CONSUME, &metapno)) == 0)
|
|
count++;
|
|
|
|
if (ret == DB_NOTFOUND)
|
|
ret = 0;
|
|
|
|
/* Discard the cursor. */
|
|
if ((t_ret = dbc->c_close(dbc)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
|
|
if (ret != 0)
|
|
return (ret);
|
|
|
|
/* update the meta page */
|
|
/* get the meta page */
|
|
metapno = ((QUEUE *)dbp->q_internal)->q_meta;
|
|
if ((ret =
|
|
__db_lget(dbc, 0, metapno, DB_LOCK_WRITE, 0, &metalock)) != 0)
|
|
return (ret);
|
|
|
|
if ((ret = mpf->get(mpf, &metapno, 0, &meta)) != 0) {
|
|
/* We did not fetch it, we can release the lock. */
|
|
(void)__LPUT(dbc, metalock);
|
|
return (ret);
|
|
}
|
|
if (DBC_LOGGING(dbc)) {
|
|
ret = __qam_mvptr_log(dbp, dbc->txn, &meta->dbmeta.lsn, 0,
|
|
QAM_SETCUR | QAM_SETFIRST | QAM_TRUNCATE, meta->first_recno,
|
|
1, meta->cur_recno, 1, &meta->dbmeta.lsn, PGNO_BASE_MD);
|
|
}
|
|
if (ret == 0)
|
|
meta->first_recno = meta->cur_recno = 1;
|
|
|
|
if ((t_ret =
|
|
mpf->put(mpf, meta, ret == 0 ? DB_MPOOL_DIRTY: 0)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
if ((t_ret = __LPUT(dbc, metalock)) != 0 && ret == 0)
|
|
ret = t_ret;
|
|
|
|
*countp = count;
|
|
|
|
return (ret);
|
|
}
|