From: Miod Vallat Date: Fri, 5 Sep 2025 08:50:19 +0000 (+0200) Subject: Add a variant of the put interface which updates the LS header in place. X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a6a4a3f480ffe0c576cdb2199f98b26c893b5b90;p=thirdparty%2Fpdns.git Add a variant of the put interface which updates the LS header in place. Signed-off-by: Miod Vallat --- diff --git a/ext/lmdb-safe/lmdb-safe.hh b/ext/lmdb-safe/lmdb-safe.hh index b653d8fed..b97eb0dd8 100644 --- a/ext/lmdb-safe/lmdb-safe.hh +++ b/ext/lmdb-safe/lmdb-safe.hh @@ -795,6 +795,22 @@ public: void clear(MDB_dbi dbi); #ifndef DNSDIST + // Write `val' without any change + void put_raw(MDB_dbi dbi, const MDBInVal& key, const MDBInVal& val, int flags = 0) + { + if (d_txn == nullptr) { + throw std::runtime_error("Attempt to use a closed RW transaction for put"); + } + + int mdbPutRc = mdb_put(d_txn, dbi, + // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) + const_cast(&key.d_mdbval), + const_cast(&val.d_mdbval), flags); + if (mdbPutRc != 0) { + throw std::runtime_error("putting data: " + MDBError(mdbPutRc)); + } + } + // Write `val' with a LSheader prepended void put(MDB_dbi dbi, const MDBInVal& key, const MDBInVal& val, int flags = 0) { if (d_txn == nullptr) { @@ -802,7 +818,6 @@ public: } size_t txid = mdb_txn_id(d_txn); - if (d_txtime == 0) { throw std::runtime_error("got zero txtime"); } @@ -811,14 +826,37 @@ public: std::string ins = LMDBLS::LSheader(d_txtime, txid).toString() + std::string((const char*)val.d_mdbval.mv_data, val.d_mdbval.mv_size); MDBInVal pval = ins; + return put_raw(dbi, key, pval, flags); + } + // Write `val', containing room for a LSheader at its beginning, with the + // header updated. + void put_header_in_place(MDB_dbi dbi, const MDBInVal& key, const MDBInVal& val, int flags = 0) + { + if (d_txn == nullptr) { + throw std::runtime_error("Attempt to use a closed RW transaction for put"); + } - int mdbPutRc = mdb_put(d_txn, dbi, - // NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast) - const_cast(&key.d_mdbval), - const_cast(&pval.d_mdbval), flags); - if (mdbPutRc != 0) { - throw std::runtime_error("putting data: " + MDBError(mdbPutRc)); + size_t txid = mdb_txn_id(d_txn); + if (d_txtime == 0) { + throw std::runtime_error("got zero txtime"); + } + + std::string header = LMDBLS::LSheader(d_txtime, txid).toString(); + // This should never happen, but better be safe than sorry. + if (val.d_mdbval.mv_size < header.length()) { + throw std::runtime_error("Data too short to contain header"); } + memcpy(val.d_mdbval.mv_data, header.c_str(), header.length()); + + return put_raw(dbi, key, val, flags); + } + // Return an empty string with reserved space for a LSheader without extra + // bytes at its beginning. + // This string should only be appended to, not assigned! + static std::string stringWithHeader() + { + std::string result(LMDBLS::LS_MIN_HEADER_SIZE, '\0'); + return result; } #else void put(MDB_dbi dbi, const MDBInVal& key, const MDBInVal& val, int flags = 0) @@ -920,6 +958,17 @@ public: ~MDBRWCursor() = default; #ifndef DNSDIST + // Write `val' without any change + void put_raw(const MDBOutVal& key, const MDBInVal& data) + { + int rc = mdb_cursor_put(*this, + const_cast(&key.d_mdbval), + const_cast(&data.d_mdbval), MDB_CURRENT); + if(rc != 0) { + throw std::runtime_error("mdb_cursor_put: " + MDBError(rc)); + } + } + // Write `val' with a LSheader prepended void put(const MDBOutVal& key, const MDBInVal& data) { size_t txid = mdb_txn_id(this->d_txn); @@ -931,13 +980,23 @@ public: std::string((const char*)data.d_mdbval.mv_data, data.d_mdbval.mv_size); MDBInVal pval = ins; + return put_raw(key, pval); + } + // Write `val', containing room for a LSheader at its beginning, with the + // header updated. + void put_header_in_place(const MDBOutVal& key, const MDBInVal& val) + { + size_t txid = mdb_txn_id(this->d_txn); - int rc = mdb_cursor_put(*this, - const_cast(&key.d_mdbval), - const_cast(&pval.d_mdbval), MDB_CURRENT); - if(rc != 0) { - throw std::runtime_error("mdb_cursor_put: " + MDBError(rc)); + if (d_txtime == 0) { throw std::runtime_error("got zero txtime"); } + + std::string header = LMDBLS::LSheader(d_txtime, txid).toString(); + // This should never happen, but better be safe than sorry. + if (val.d_mdbval.mv_size < header.length()) { + throw std::runtime_error("Data too short to contain header"); } + memcpy(val.d_mdbval.mv_data, header.c_str(), header.length()); + return put_raw(key, val); } #else void put(const MDBOutVal& key, const MDBInVal& data)