|
|
@ -1037,6 +1037,7 @@ struct MDB_txn { |
|
|
|
#define DB_STALE 0x02 /**< Named-DB record is older than txnID */ |
|
|
|
#define DB_STALE 0x02 /**< Named-DB record is older than txnID */ |
|
|
|
#define DB_NEW 0x04 /**< Named-DB handle opened in this txn */ |
|
|
|
#define DB_NEW 0x04 /**< Named-DB handle opened in this txn */ |
|
|
|
#define DB_VALID 0x08 /**< DB handle is valid, see also #MDB_VALID */ |
|
|
|
#define DB_VALID 0x08 /**< DB handle is valid, see also #MDB_VALID */ |
|
|
|
|
|
|
|
#define DB_USRVALID 0x10 /**< As #DB_VALID, but not set for #FREE_DBI */ |
|
|
|
/** @} */ |
|
|
|
/** @} */ |
|
|
|
/** In write txns, array of cursors for each DB */ |
|
|
|
/** In write txns, array of cursors for each DB */ |
|
|
|
MDB_cursor **mt_cursors; |
|
|
|
MDB_cursor **mt_cursors; |
|
|
@ -1227,8 +1228,8 @@ typedef struct MDB_ntxn { |
|
|
|
#define MAX_WRITE (0x80000000U >> (sizeof(ssize_t) == 4)) |
|
|
|
#define MAX_WRITE (0x80000000U >> (sizeof(ssize_t) == 4)) |
|
|
|
|
|
|
|
|
|
|
|
/** Check \b txn and \b dbi arguments to a function */ |
|
|
|
/** Check \b txn and \b dbi arguments to a function */ |
|
|
|
#define TXN_DBI_EXIST(txn, dbi) \ |
|
|
|
#define TXN_DBI_EXIST(txn, dbi, validity) \ |
|
|
|
((txn) && (dbi) < (txn)->mt_numdbs && ((txn)->mt_dbflags[dbi] & DB_VALID)) |
|
|
|
((txn) && (dbi)<(txn)->mt_numdbs && ((txn)->mt_dbflags[dbi] & (validity))) |
|
|
|
|
|
|
|
|
|
|
|
/** Check for misused \b dbi handles */ |
|
|
|
/** Check for misused \b dbi handles */ |
|
|
|
#define TXN_DBI_CHANGED(txn, dbi) \ |
|
|
|
#define TXN_DBI_CHANGED(txn, dbi) \ |
|
|
@ -2662,9 +2663,10 @@ mdb_txn_renew0(MDB_txn *txn) |
|
|
|
for (i=2; i<txn->mt_numdbs; i++) { |
|
|
|
for (i=2; i<txn->mt_numdbs; i++) { |
|
|
|
x = env->me_dbflags[i]; |
|
|
|
x = env->me_dbflags[i]; |
|
|
|
txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS; |
|
|
|
txn->mt_dbs[i].md_flags = x & PERSISTENT_FLAGS; |
|
|
|
txn->mt_dbflags[i] = (x & MDB_VALID) ? DB_VALID|DB_STALE : 0; |
|
|
|
txn->mt_dbflags[i] = (x & MDB_VALID) ? DB_VALID|DB_USRVALID|DB_STALE : 0; |
|
|
|
} |
|
|
|
} |
|
|
|
txn->mt_dbflags[0] = txn->mt_dbflags[1] = DB_VALID; |
|
|
|
txn->mt_dbflags[MAIN_DBI] = DB_VALID|DB_USRVALID; |
|
|
|
|
|
|
|
txn->mt_dbflags[FREE_DBI] = DB_VALID; |
|
|
|
|
|
|
|
|
|
|
|
if (env->me_maxpg < txn->mt_next_pgno) { |
|
|
|
if (env->me_maxpg < txn->mt_next_pgno) { |
|
|
|
mdb_txn_reset0(txn, "renew0-mapfail"); |
|
|
|
mdb_txn_reset0(txn, "renew0-mapfail"); |
|
|
@ -5466,7 +5468,7 @@ mdb_get(MDB_txn *txn, MDB_dbi dbi, |
|
|
|
|
|
|
|
|
|
|
|
DPRINTF(("===> get db %u key [%s]", dbi, DKEY(key))); |
|
|
|
DPRINTF(("===> get db %u key [%s]", dbi, DKEY(key))); |
|
|
|
|
|
|
|
|
|
|
|
if (!key || !data || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi)) |
|
|
|
if (!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
if (txn->mt_flags & MDB_TXN_ERROR) |
|
|
|
if (txn->mt_flags & MDB_TXN_ERROR) |
|
|
@ -7207,7 +7209,7 @@ mdb_xcursor_init1(MDB_cursor *mc, MDB_node *node) |
|
|
|
} |
|
|
|
} |
|
|
|
DPRINTF(("Sub-db -%u root page %"Z"u", mx->mx_cursor.mc_dbi, |
|
|
|
DPRINTF(("Sub-db -%u root page %"Z"u", mx->mx_cursor.mc_dbi, |
|
|
|
mx->mx_db.md_root)); |
|
|
|
mx->mx_db.md_root)); |
|
|
|
mx->mx_dbflag = DB_VALID|DB_DIRTY; /* DB_DIRTY guides mdb_cursor_touch */ |
|
|
|
mx->mx_dbflag = DB_VALID|DB_USRVALID|DB_DIRTY; /* DB_DIRTY guides mdb_cursor_touch */ |
|
|
|
#if UINT_MAX < SIZE_MAX |
|
|
|
#if UINT_MAX < SIZE_MAX |
|
|
|
if (mx->mx_dbx.md_cmp == mdb_cmp_int && mx->mx_db.md_pad == sizeof(size_t)) |
|
|
|
if (mx->mx_dbx.md_cmp == mdb_cmp_int && mx->mx_db.md_pad == sizeof(size_t)) |
|
|
|
mx->mx_dbx.md_cmp = mdb_cmp_clong; |
|
|
|
mx->mx_dbx.md_cmp = mdb_cmp_clong; |
|
|
@ -7280,7 +7282,7 @@ mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret) |
|
|
|
MDB_cursor *mc; |
|
|
|
MDB_cursor *mc; |
|
|
|
size_t size = sizeof(MDB_cursor); |
|
|
|
size_t size = sizeof(MDB_cursor); |
|
|
|
|
|
|
|
|
|
|
|
if (!ret || !TXN_DBI_EXIST(txn, dbi)) |
|
|
|
if (!ret || !TXN_DBI_EXIST(txn, dbi, DB_VALID)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
if (txn->mt_flags & MDB_TXN_ERROR) |
|
|
|
if (txn->mt_flags & MDB_TXN_ERROR) |
|
|
@ -7312,7 +7314,7 @@ mdb_cursor_open(MDB_txn *txn, MDB_dbi dbi, MDB_cursor **ret) |
|
|
|
int |
|
|
|
int |
|
|
|
mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc) |
|
|
|
mdb_cursor_renew(MDB_txn *txn, MDB_cursor *mc) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!mc || !TXN_DBI_EXIST(txn, mc->mc_dbi)) |
|
|
|
if (!mc || !TXN_DBI_EXIST(txn, mc->mc_dbi, DB_VALID)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
if ((mc->mc_flags & C_UNTRACK) || txn->mt_cursors) |
|
|
|
if ((mc->mc_flags & C_UNTRACK) || txn->mt_cursors) |
|
|
@ -8084,7 +8086,7 @@ int |
|
|
|
mdb_del(MDB_txn *txn, MDB_dbi dbi, |
|
|
|
mdb_del(MDB_txn *txn, MDB_dbi dbi, |
|
|
|
MDB_val *key, MDB_val *data) |
|
|
|
MDB_val *key, MDB_val *data) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!key || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi)) |
|
|
|
if (!key || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_ERROR)) |
|
|
|
if (txn->mt_flags & (MDB_TXN_RDONLY|MDB_TXN_ERROR)) |
|
|
@ -8550,7 +8552,7 @@ mdb_put(MDB_txn *txn, MDB_dbi dbi, |
|
|
|
MDB_cursor mc; |
|
|
|
MDB_cursor mc; |
|
|
|
MDB_xcursor mx; |
|
|
|
MDB_xcursor mx; |
|
|
|
|
|
|
|
|
|
|
|
if (!key || !data || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi)) |
|
|
|
if (!key || !data || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
if (flags & ~(MDB_NOOVERWRITE|MDB_NODUPDATA|MDB_RESERVE|MDB_APPEND|MDB_APPENDDUP)) |
|
|
|
if (flags & ~(MDB_NOOVERWRITE|MDB_NODUPDATA|MDB_RESERVE|MDB_APPEND|MDB_APPENDDUP)) |
|
|
@ -9320,7 +9322,7 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *db |
|
|
|
return (flags & MDB_CREATE) ? MDB_INCOMPATIBLE : MDB_NOTFOUND; |
|
|
|
return (flags & MDB_CREATE) ? MDB_INCOMPATIBLE : MDB_NOTFOUND; |
|
|
|
|
|
|
|
|
|
|
|
/* Find the DB info */ |
|
|
|
/* Find the DB info */ |
|
|
|
dbflag = DB_NEW|DB_VALID; |
|
|
|
dbflag = DB_NEW|DB_VALID|DB_USRVALID; |
|
|
|
exact = 0; |
|
|
|
exact = 0; |
|
|
|
key.mv_size = len; |
|
|
|
key.mv_size = len; |
|
|
|
key.mv_data = (void *)name; |
|
|
|
key.mv_data = (void *)name; |
|
|
@ -9368,7 +9370,7 @@ int mdb_dbi_open(MDB_txn *txn, const char *name, unsigned int flags, MDB_dbi *db |
|
|
|
|
|
|
|
|
|
|
|
int mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg) |
|
|
|
int mdb_stat(MDB_txn *txn, MDB_dbi dbi, MDB_stat *arg) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (!arg || !TXN_DBI_EXIST(txn, dbi)) |
|
|
|
if (!arg || !TXN_DBI_EXIST(txn, dbi, DB_VALID)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
if (txn->mt_flags & MDB_TXN_ERROR) |
|
|
|
if (txn->mt_flags & MDB_TXN_ERROR) |
|
|
@ -9402,7 +9404,7 @@ void mdb_dbi_close(MDB_env *env, MDB_dbi dbi) |
|
|
|
int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags) |
|
|
|
int mdb_dbi_flags(MDB_txn *txn, MDB_dbi dbi, unsigned int *flags) |
|
|
|
{ |
|
|
|
{ |
|
|
|
/* We could return the flags for the FREE_DBI too but what's the point? */ |
|
|
|
/* We could return the flags for the FREE_DBI too but what's the point? */ |
|
|
|
if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi)) |
|
|
|
if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
*flags = txn->mt_dbs[dbi].md_flags & PERSISTENT_FLAGS; |
|
|
|
*flags = txn->mt_dbs[dbi].md_flags & PERSISTENT_FLAGS; |
|
|
|
return MDB_SUCCESS; |
|
|
|
return MDB_SUCCESS; |
|
|
@ -9502,7 +9504,7 @@ int mdb_drop(MDB_txn *txn, MDB_dbi dbi, int del) |
|
|
|
MDB_cursor *mc, *m2; |
|
|
|
MDB_cursor *mc, *m2; |
|
|
|
int rc; |
|
|
|
int rc; |
|
|
|
|
|
|
|
|
|
|
|
if ((unsigned)del > 1 || dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi)) |
|
|
|
if ((unsigned)del > 1 || !TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) |
|
|
|
if (F_ISSET(txn->mt_flags, MDB_TXN_RDONLY)) |
|
|
@ -9550,7 +9552,7 @@ leave: |
|
|
|
|
|
|
|
|
|
|
|
int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp) |
|
|
|
int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi)) |
|
|
|
if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
txn->mt_dbxs[dbi].md_cmp = cmp; |
|
|
|
txn->mt_dbxs[dbi].md_cmp = cmp; |
|
|
@ -9559,7 +9561,7 @@ int mdb_set_compare(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp) |
|
|
|
|
|
|
|
|
|
|
|
int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp) |
|
|
|
int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi)) |
|
|
|
if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
txn->mt_dbxs[dbi].md_dcmp = cmp; |
|
|
|
txn->mt_dbxs[dbi].md_dcmp = cmp; |
|
|
@ -9568,7 +9570,7 @@ int mdb_set_dupsort(MDB_txn *txn, MDB_dbi dbi, MDB_cmp_func *cmp) |
|
|
|
|
|
|
|
|
|
|
|
int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel) |
|
|
|
int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi)) |
|
|
|
if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
txn->mt_dbxs[dbi].md_rel = rel; |
|
|
|
txn->mt_dbxs[dbi].md_rel = rel; |
|
|
@ -9577,7 +9579,7 @@ int mdb_set_relfunc(MDB_txn *txn, MDB_dbi dbi, MDB_rel_func *rel) |
|
|
|
|
|
|
|
|
|
|
|
int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx) |
|
|
|
int mdb_set_relctx(MDB_txn *txn, MDB_dbi dbi, void *ctx) |
|
|
|
{ |
|
|
|
{ |
|
|
|
if (dbi == FREE_DBI || !TXN_DBI_EXIST(txn, dbi)) |
|
|
|
if (!TXN_DBI_EXIST(txn, dbi, DB_USRVALID)) |
|
|
|
return EINVAL; |
|
|
|
return EINVAL; |
|
|
|
|
|
|
|
|
|
|
|
txn->mt_dbxs[dbi].md_relctx = ctx; |
|
|
|
txn->mt_dbxs[dbi].md_relctx = ctx; |
|
|
|