diff --git a/mdbx.h b/mdbx.h index 2af8b66f..ae9e5ca5 100644 --- a/mdbx.h +++ b/mdbx.h @@ -1759,6 +1759,9 @@ LIBMDBX_API int mdbx_dbi_open_ex(MDB_txn *txn, const char *name, unsigned flags, MDB_dbi *dbi, MDB_cmp_func *keycmp, MDB_cmp_func *datacmp); +LIBMDBX_API int mdbx_dbi_sequence(MDB_txn *txn, MDB_dbi dbi, uint64_t *result, + uint64_t increment); + #ifdef __cplusplus } #endif diff --git a/src/bits.h b/src/bits.h index 70cfaa48..c57fa8c3 100644 --- a/src/bits.h +++ b/src/bits.h @@ -246,6 +246,7 @@ typedef struct MDB_db { uint32_t md_xsize; /**< also ksize for LEAF2 pages */ uint16_t md_flags; /**< @ref mdbx_dbi_open */ uint16_t md_depth; /**< depth of this tree */ + uint64_t md_seq; /* table sequence counter */ pgno_t md_branch_pages; /**< number of internal pages */ pgno_t md_leaf_pages; /**< number of leaf pages */ pgno_t md_overflow_pages; /**< number of overflow pages */ diff --git a/src/mdbx.c b/src/mdbx.c index eb29d3ab..d48994be 100644 --- a/src/mdbx.c +++ b/src/mdbx.c @@ -9073,6 +9073,7 @@ int mdbx_drop(MDB_txn *txn, MDB_dbi dbi, int del) { txn->mt_dbs[dbi].md_overflow_pages = 0; txn->mt_dbs[dbi].md_entries = 0; txn->mt_dbs[dbi].md_root = P_INVALID; + txn->mt_dbs[dbi].md_seq = 0; txn->mt_flags |= MDB_TXN_DIRTY; } @@ -10241,3 +10242,41 @@ int mdbx_dbi_open_ex(MDB_txn *txn, const char *name, unsigned flags, } return rc; } + +int mdbx_dbi_sequence(MDB_txn *txn, MDB_dbi dbi, uint64_t *result, + uint64_t increment) { + if (unlikely(!txn)) + return EINVAL; + + if (unlikely(txn->mt_signature != MDBX_MT_SIGNATURE)) + return MDBX_EBADSIGN; + + if (unlikely(!TXN_DBI_EXIST(txn, dbi, DB_USRVALID))) + return EINVAL; + + if (unlikely(TXN_DBI_CHANGED(txn, dbi))) + return MDB_BAD_DBI; + + MDB_db *dbs = &txn->mt_dbs[dbi]; + if (likely(result)) + *result = dbs->md_seq; + + if (likely(increment > 0)) { + if (unlikely(txn->mt_flags & MDB_TXN_BLOCKED)) + return MDB_BAD_TXN; + + if (unlikely(F_ISSET(txn->mt_flags, MDB_TXN_RDONLY))) + return EACCES; + + uint64_t new = dbs->md_seq + increment; + if (unlikely(new < increment)) + return MDBX_RESULT_TRUE; + + assert(new > dbs->md_seq); + dbs->md_seq = new; + txn->mt_flags |= MDB_TXN_DIRTY; + txn->mt_dbflags[dbi] |= DB_DIRTY; + } + + return MDB_SUCCESS; +}