From ff0e58996281577e9d7065d33f5a8db3a6bee508 Mon Sep 17 00:00:00 2001 From: Miod Vallat Date: Thu, 17 Jul 2025 12:43:26 +0200 Subject: [PATCH] Add a few "peek" routines... ...which look at specific record fields without performing a complete deserialization, especially the memcpy of the record payload. This (hopefully) allows for faster operation, especially during NSEC3 record maintainance. Signed-off-by: Miod Vallat --- modules/lmdbbackend/lmdbbackend.cc | 99 +++++++++++++++++++++--------- modules/lmdbbackend/lmdbbackend.hh | 2 +- 2 files changed, 70 insertions(+), 31 deletions(-) diff --git a/modules/lmdbbackend/lmdbbackend.cc b/modules/lmdbbackend/lmdbbackend.cc index 2d18957098..144ef3a810 100644 --- a/modules/lmdbbackend/lmdbbackend.cc +++ b/modules/lmdbbackend/lmdbbackend.cc @@ -1092,6 +1092,40 @@ static std::shared_ptr deserializeContentZR(uint16_t qtype, co return DNSRecordContent::deserialize(qname, qtype, content, QClass::IN, true); } +// For the few places where we are only interested in the hasOrderName field, +// this cheap routine is faster than doing: +// { +// LMDBResourceRecord lrr; +// deserializeFromBuffer(buffer, lrr); +// return lrr.hasOrderName; +// } +static bool peekAtHasOrderName(const string_view& buffer) +{ + uint16_t len; + memcpy(&len, &buffer[0], 2); + bool hasOrderName = buffer[2 + len + 4 + 2] != 0; + return hasOrderName; +} + +// Similar to the above, but for the auth field. +static bool peekAtAuth(const string_view& buffer) +{ + uint16_t len; + memcpy(&len, &buffer[0], 2); + bool auth = buffer[2 + len + 4] != 0; + return auth; +} + +// Similar to the above, but for the ttl. +static uint32_t peekAtTtl(const string_view& buffer) +{ + uint16_t len; + memcpy(&len, &buffer[0], 2); + uint32_t ttl; + memcpy(&ttl, &buffer[2] + len, 4); + return ttl; +} + /* A note on the design. If you ask a question without a zone id (this can be the case for lookup(), @@ -1389,9 +1423,7 @@ bool LMDBBackend::replaceRRSet(domainid_t domain_id, const DNSName& qname, const match = co(domain_id, relative, qt.getCode()); // There should be at most one exact match here. if (cursor.find(match, key, val) == 0) { - LMDBResourceRecord lrr; - deserializeFromBuffer(val.get(), lrr); - hadOrderName = lrr.hasOrderName; + hadOrderName = peekAtHasOrderName(val.get()); cursor.del(key); } // If we are not going to add any new records, check if there are any @@ -2472,12 +2504,10 @@ bool LMDBBackend::unpublishDomainKey(const ZoneName& name, unsigned int keyId) } // Return true if the key points to an NSEC3 back chain record (ttl == 0). -// Updates lrr if this is an NSEC3 record (regardless of its kind). -bool LMDBBackend::isNSEC3BackRecord(LMDBResourceRecord& lrr, const MDBOutVal& key, const MDBOutVal& val) +bool LMDBBackend::isNSEC3BackRecord(const MDBOutVal& key, const MDBOutVal& val) { if (compoundOrdername::getQType(key.getNoStripHeader()) == QType::NSEC3) { - deserializeFromBuffer(val.get(), lrr); - if (lrr.ttl == 0) { + if (peekAtTtl(val.get()) == 0) { return true; } } @@ -2490,9 +2520,7 @@ bool LMDBBackend::isNSEC3BackRecord(LMDBResourceRecord& lrr, const MDBOutVal& ke // NOLINTNEXTLINE(readability-identifier-length) bool LMDBBackend::getAfterForward(MDBROCursor& cursor, MDBOutVal& key, MDBOutVal& val, domainid_t id, DNSName& after) { - LMDBResourceRecord lrr; - - while (!isNSEC3BackRecord(lrr, key, val)) { + while (!isNSEC3BackRecord(key, val)) { if (cursor.next(key, val) != 0 || compoundOrdername::getDomainID(key.getNoStripHeader()) != id) { // cout<<"hit end of zone or database when we shouldn't"<txn->getCursor(txn->db->dbi); MDBOutVal key, val; - LMDBResourceRecord lrr; - string matchkey = co(id, qname, QType::NSEC3); if (cursor.lower_bound(matchkey, key, val)) { // this is beyond the end of the database @@ -2549,7 +2575,7 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(domainid_t id, const DNSName& q return false; } - if (isNSEC3BackRecord(lrr, key, val)) { + if (isNSEC3BackRecord(key, val)) { break; // the kind of NSEC3 we need } if (cursor.prev(key, val)) { @@ -2558,8 +2584,11 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(domainid_t id, const DNSName& q } } before = co.getQName(key.getNoStripHeader()); - unhashed = DNSName(lrr.content.c_str(), lrr.content.size(), 0, false) + di.zone.operator const DNSName&(); - + { + LMDBResourceRecord lrr; + deserializeFromBuffer(val.get(), lrr); + unhashed = DNSName(lrr.content.c_str(), lrr.content.size(), 0, false) + di.zone.operator const DNSName&(); + } // now to find after .. at the beginning of the zone return getAfterForwardFromStart(cursor, key, val, id, after); } @@ -2581,7 +2610,7 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(domainid_t id, const DNSName& q int count = 0; for (;;) { if (compoundOrdername::getQName(key.getNoStripHeader()).canonCompare(qname)) { - if (isNSEC3BackRecord(lrr, key, val)) { + if (isNSEC3BackRecord(key, val)) { break; } } @@ -2605,7 +2634,7 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(domainid_t id, const DNSName& q return false; } - if (isNSEC3BackRecord(lrr, key, val)) { + if (isNSEC3BackRecord(key, val)) { break; } if (cursor.prev(key, val)) { @@ -2614,7 +2643,11 @@ bool LMDBBackend::getBeforeAndAfterNamesAbsolute(domainid_t id, const DNSName& q } } before = co.getQName(key.getNoStripHeader()); - unhashed = DNSName(lrr.content.c_str(), lrr.content.size(), 0, false) + di.zone.operator const DNSName&(); + { + LMDBResourceRecord lrr; + deserializeFromBuffer(val.get(), lrr); + unhashed = DNSName(lrr.content.c_str(), lrr.content.size(), 0, false) + di.zone.operator const DNSName&(); + } // cout <<"Should still find 'after'!"<()); - unhashed = DNSName(lrr.content.c_str(), lrr.content.size(), 0, false) + di.zone.operator const DNSName&(); + { + LMDBResourceRecord lrr; + deserializeFromBuffer(val.get(), lrr); + unhashed = DNSName(lrr.content.c_str(), lrr.content.size(), 0, false) + di.zone.operator const DNSName&(); + } // cout<<"Went backwards, found "<(), lrr); QType qtype = compoundOrdername::getQType(key.getNoStripHeader()).getCode(); - return qtype != QType::ENT && (lrr.auth || qtype == QType::NS); + switch (qtype) { + case QType::ENT: + return false; + case QType::NS: + return true; + default: + return peekAtAuth(val.get()); + } } bool LMDBBackend::getBeforeAndAfterNames(domainid_t domainId, const ZoneName& zonenameU, const DNSName& qname, DNSName& before, DNSName& after) @@ -2902,9 +2944,7 @@ bool LMDBBackend::updateEmptyNonTerminals(domainid_t domain_id, set& in // as to remove the matching NSEC3 records, if any. // (we can't invoke deleteNSEC3RecordPair here as doing this // could make our cursor invalid) - LMDBResourceRecord lrr; - deserializeFromBuffer(val.get(), lrr); - if (lrr.hasOrderName) { + if (peekAtHasOrderName(val.get())) { DNSName qname = compoundOrdername::getQName(key.getNoStripHeader()); names.emplace_back(qname); } @@ -2930,10 +2970,9 @@ bool LMDBBackend::updateEmptyNonTerminals(domainid_t domain_id, set& in std::string match = order(domain_id, name, QType::ENT); MDBOutVal val{}; if (txn->txn->get(txn->db->dbi, match, val) == 0) { - LMDBResourceRecord lrr; - deserializeFromBuffer(val.get(), lrr); + bool hadOrderName = peekAtHasOrderName(val.get()); txn->txn->del(txn->db->dbi, match); - if (lrr.hasOrderName) { + if (hadOrderName) { deleteNSEC3RecordPair(txn, domain_id, name); } } diff --git a/modules/lmdbbackend/lmdbbackend.hh b/modules/lmdbbackend/lmdbbackend.hh index 1071a50731..80a3d46f86 100644 --- a/modules/lmdbbackend/lmdbbackend.hh +++ b/modules/lmdbbackend/lmdbbackend.hh @@ -345,7 +345,7 @@ private: static bool getAfterForward(MDBROCursor& cursor, MDBOutVal& key, MDBOutVal& val, domainid_t id, DNSName& after); static bool getAfterForwardFromStart(MDBROCursor& cursor, MDBOutVal& key, MDBOutVal& val, domainid_t id, DNSName& after); - static bool isNSEC3BackRecord(LMDBResourceRecord& lrr, const MDBOutVal& key, const MDBOutVal& val); + static bool isNSEC3BackRecord(const MDBOutVal& key, const MDBOutVal& val); static bool isValidAuthRecord(const MDBOutVal& key, const MDBOutVal& val); static bool hasOrphanedNSEC3Record(MDBRWCursor& cursor, domainid_t domain_id, const DNSName& qname); static void deleteNSEC3RecordPair(const std::shared_ptr& txn, domainid_t domain_id, const DNSName& qname); -- 2.47.3