return true;
}
+// Serial number cache
+bool LMDBBackend::SerialCache::get(domainid_t domainid, uint32_t& serial) const
+{
+ if (auto iter = d_serials.find(domainid); iter != d_serials.end()) {
+ serial = iter->second;
+ return true;
+ }
+ return false;
+}
+
+void LMDBBackend::SerialCache::remove(domainid_t domainid)
+{
+ if (auto iter = d_serials.find(domainid); iter != d_serials.end()) {
+ d_serials.erase(iter);
+ }
+}
+
+void LMDBBackend::SerialCache::update(domainid_t domainid, uint32_t serial)
+{
+ d_serials.insert_or_assign(domainid, serial);
+}
+
+SharedLockGuarded<LMDBBackend::SerialCache> LMDBBackend::s_notified_serial;
+
LMDBBackend::LMDBBackend(const std::string& suffix)
{
// overlapping domain ids in combination with relative names are a recipe for disaster
throw std::runtime_error(std::string("Unable to parse the 'map-size' LMDB value: ") + e.what());
}
+ d_skip_notification_update = mustDo("skip-notification-update");
+
if (mustDo("lightning-stream")) {
d_random_ids = true;
d_handle_dups = true;
}
}
-bool LMDBBackend::findDomain(const ZoneName& domain, DomainInfo& info)
+bool LMDBBackend::findDomain(const ZoneName& domain, DomainInfo& info) const
{
auto rotxn = d_tdomains->getROTransaction();
auto domain_id = rotxn.get<0>(domain, info);
return true;
}
-bool LMDBBackend::findDomain(domainid_t domainid, DomainInfo& info)
+bool LMDBBackend::findDomain(domainid_t domainid, DomainInfo& info) const
{
auto rotxn = d_tdomains->getROTransaction();
if (!rotxn.get(domainid, info)) {
return true;
}
+void LMDBBackend::consolidateDomainInfo(DomainInfo& info) const
+{
+ // Update the notified_serial value if we have a cached value in memory.
+ if (d_skip_notification_update) {
+ auto container = s_notified_serial.read_lock();
+ container->get(info.id, info.notified_serial);
+ }
+}
+
+void LMDBBackend::writeDomainInfo(const DomainInfo& info)
+{
+ if (d_skip_notification_update) {
+ uint32_t last_notified_serial{0};
+ auto container = s_notified_serial.write_lock();
+ container->get(info.id, last_notified_serial);
+ // Only remove the in-memory value if it has not been modified since the
+ // DomainInfo data was set up.
+ if (last_notified_serial == info.notified_serial) {
+ container->remove(info.id);
+ }
+ }
+ auto txn = d_tdomains->getRWTransaction();
+ txn.put(info, info.id);
+ txn.commit();
+}
+
/* Here's the complicated story. Other backends have just one transaction, which is either
on or not.
commitTransaction();
// Remove zone
+ {
+ auto container = s_notified_serial.write_lock();
+ container->remove(static_cast<domainid_t>(id));
+ }
auto txn = d_tdomains->getRWTransaction();
txn.del(id);
txn.commit();
return false;
}
info.backend = this;
+ consolidateDomainInfo(info);
if (getserial) {
getSerial(info);
if (!findDomain(domain, info)) {
return false;
}
+ consolidateDomainInfo(info);
func(info);
- auto txn = d_tdomains->getRWTransaction();
- txn.put(info, info.id);
- txn.commit();
+ writeDomainInfo(info);
return true;
}
if (!findDomain(id, info)) {
return false;
}
+ consolidateDomainInfo(info);
func(info);
- auto txn = d_tdomains->getRWTransaction();
- txn.put(info, id);
- txn.commit();
+ writeDomainInfo(info);
return true;
}
for (auto& [k, v] : zonemap) {
if (allow(v)) {
+ consolidateDomainInfo(v);
domains->push_back(std::move(v));
}
}
di.backend = this;
if (allow(di)) {
+ consolidateDomainInfo(di);
domains->push_back(di);
}
}
void LMDBBackend::setNotified(domainid_t domain_id, uint32_t serial)
{
- genChangeDomain(domain_id, [serial](DomainInfo& info) {
- info.notified_serial = serial;
- });
+ if (!d_skip_notification_update) {
+ genChangeDomain(domain_id, [serial](DomainInfo& info) {
+ info.notified_serial = serial;
+ });
+ return;
+ }
+
+ DomainInfo info;
+ if (findDomain(domain_id, info)) {
+ auto container = s_notified_serial.write_lock();
+ container->update(info.id, serial);
+ }
+ // else throw something? this should be a "can't happen" situation.
}
class getCatalogMembersReturnFalseException : std::runtime_error
declare(suffix, "random-ids", "Numeric IDs inside the database are generated randomly instead of sequentially", "no");
declare(suffix, "map-size", "LMDB map size in megabytes", (sizeof(void*) == 4) ? "100" : "16000");
declare(suffix, "flag-deleted", "Flag entries on deletion instead of deleting them", "no");
+ declare(suffix, "skip-notification-update", "Do not update domain table upon notification", "no");
declare(suffix, "lightning-stream", "Run in Lightning Stream compatible mode", "no");
}
DNSBackend* make(const string& suffix = "") override
bool genChangeDomain(domainid_t id, const std::function<void(DomainInfo&)>& func);
static void deleteDomainRecords(RecordsRWTransaction& txn, const std::string& match, QType qtype = QType::ANY);
- bool findDomain(const ZoneName& domain, DomainInfo& info);
- bool findDomain(domainid_t domainid, DomainInfo& info);
+ bool findDomain(const ZoneName& domain, DomainInfo& info) const;
+ bool findDomain(domainid_t domainid, DomainInfo& info) const;
+ void consolidateDomainInfo(DomainInfo& info) const;
+ void writeDomainInfo(const DomainInfo& info);
void getAllDomainsFiltered(vector<DomainInfo>* domains, const std::function<bool(DomainInfo&)>& allow);
string directBackendCmd_list(std::vector<string>& argv);
+ // Cache of DomainInfo notified_serial values
+ class SerialCache : public boost::noncopyable
+ {
+ public:
+ bool get(domainid_t domainid, uint32_t& serial) const;
+ void remove(domainid_t domainid);
+ void update(domainid_t domainid, uint32_t serial);
+
+ private:
+ std::unordered_map<domainid_t, uint32_t> d_serials;
+ };
+ static SharedLockGuarded<SerialCache> s_notified_serial;
+
ZoneName d_lookupdomain;
DNSName d_lookupsubmatch;
vector<LMDBResourceRecord> d_currentrrset;
bool d_random_ids;
bool d_handle_dups;
bool d_views;
+ bool d_skip_notification_update;
DTime d_dtime; // used only for logging
uint64_t d_mapsize;
};