Avoid overflow when running out of IDs
* Throw an exception instead * Add function that allows re-using lower IDs instead * Move functions to query IDs to read-only operations
This commit is contained in:
parent
7689f0ebd6
commit
bb985870f0
|
@ -2,15 +2,4 @@
|
||||||
|
|
||||||
namespace LMDBSafe {
|
namespace LMDBSafe {
|
||||||
|
|
||||||
IDType MDBGetMaxID(MDBRWTransaction &txn, MDBDbi &dbi)
|
|
||||||
{
|
|
||||||
auto cursor = txn->getRWCursor(dbi);
|
|
||||||
MDBOutVal maxidval, maxcontent;
|
|
||||||
auto maxid = IDType(0);
|
|
||||||
if (!cursor.get(maxidval, maxcontent, MDB_LAST)) {
|
|
||||||
maxid = maxidval.get<IDType>();
|
|
||||||
}
|
|
||||||
return maxid;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace LMDBSafe
|
} // namespace LMDBSafe
|
||||||
|
|
|
@ -13,14 +13,6 @@ namespace LMDBSafe {
|
||||||
*/
|
*/
|
||||||
using IDType = std::uint32_t;
|
using IDType = std::uint32_t;
|
||||||
|
|
||||||
/*!
|
|
||||||
* \brief Returns the highest ID used in a database. Returns 0 for an empty DB.
|
|
||||||
* \remarks
|
|
||||||
* This makes us start everything at ID "1", which might make it possible to
|
|
||||||
* treat id 0 as special.
|
|
||||||
*/
|
|
||||||
LMDB_SAFE_EXPORT IDType MDBGetMaxID(MDBRWTransaction &txn, MDBDbi &dbi);
|
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
* \brief Converts \a t to an std::string.
|
* \brief Converts \a t to an std::string.
|
||||||
*
|
*
|
||||||
|
@ -298,6 +290,63 @@ public:
|
||||||
return stat.ms_entries;
|
return stat.ms_entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the highest ID or 0 if the database is empty.
|
||||||
|
*/
|
||||||
|
IDType maxID()
|
||||||
|
{
|
||||||
|
auto cursor = (*d_parent.d_txn)->getCursor(d_parent.d_parent->d_main);
|
||||||
|
MDBOutVal idval, maxcontent;
|
||||||
|
auto id = IDType(0);
|
||||||
|
if (!cursor.get(idval, maxcontent, MDB_LAST)) {
|
||||||
|
id = idval.get<IDType>();
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns the next highest ID in the database.
|
||||||
|
* \remarks Never returns 0 so it can be used as special "no such ID" value.
|
||||||
|
* \throws Throws LMDBError when running out of IDs.
|
||||||
|
*/
|
||||||
|
IDType nextID()
|
||||||
|
{
|
||||||
|
const auto id = maxID();
|
||||||
|
if (id < std::numeric_limits<IDType>::max()) {
|
||||||
|
return id + 1;
|
||||||
|
}
|
||||||
|
throw LMDBError("Running out of IDs");
|
||||||
|
}
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* \brief Returns an ID not used in the database so far.
|
||||||
|
* \remarks
|
||||||
|
* - Lower IDs are reused but an extensive search for "gabs" is avoided.
|
||||||
|
* - Never returns 0 so it can be used as special "no such ID" value.
|
||||||
|
* \throws Throws LMDBError when running out of IDs.
|
||||||
|
*/
|
||||||
|
IDType newID()
|
||||||
|
{
|
||||||
|
auto cursor = (*d_parent.d_txn)->getCursor(d_parent.d_parent->d_main);
|
||||||
|
MDBOutVal idval, maxcontent;
|
||||||
|
auto id = IDType(1);
|
||||||
|
if (!cursor.get(idval, maxcontent, MDB_FIRST)) {
|
||||||
|
id = idval.get<IDType>();
|
||||||
|
}
|
||||||
|
if (id > 1) {
|
||||||
|
return id - 1;
|
||||||
|
}
|
||||||
|
if (!cursor.get(idval, maxcontent, MDB_LAST)) {
|
||||||
|
id = idval.get<IDType>();
|
||||||
|
} else {
|
||||||
|
id = 0;
|
||||||
|
}
|
||||||
|
if (id < std::numeric_limits<IDType>::max()) {
|
||||||
|
return id + 1;
|
||||||
|
}
|
||||||
|
throw LMDBError("Running out of IDs");
|
||||||
|
}
|
||||||
|
|
||||||
//! Get item with id, from main table directly
|
//! Get item with id, from main table directly
|
||||||
bool get(IDType id, T &t)
|
bool get(IDType id, T &t)
|
||||||
{
|
{
|
||||||
|
@ -798,7 +847,7 @@ public:
|
||||||
{
|
{
|
||||||
unsigned int flags = 0;
|
unsigned int flags = 0;
|
||||||
if (!id) {
|
if (!id) {
|
||||||
id = MDBGetMaxID(*d_txn, d_parent->d_main) + 1;
|
id = this->nextID();
|
||||||
flags = MDB_APPEND;
|
flags = MDB_APPEND;
|
||||||
}
|
}
|
||||||
(*d_txn)->put(d_parent->d_main, id, serToString(t), flags);
|
(*d_txn)->put(d_parent->d_main, id, serToString(t), flags);
|
||||||
|
|
Loading…
Reference in New Issue