#define DNS_DBADD_EXACT 0x04
#define DNS_DBADD_EXACTTTL 0x08
#define DNS_DBADD_PREFETCH 0x10
+#define DNS_DBADD_EQUALOK 0x20
/*@}*/
/*%
* the old and new rdata sets. If #DNS_DBADD_EXACTTTL is set then both
* the old and new rdata sets must have the same ttl.
*
+ * \li If the #DNS_DBADD_EQUALOK option is set, and the database is not
+ * changed, compare the old and new rdatasets; if they are equal,
+ * return #ISC_R_SUCCESS instead of #DNS_R_UNCHANGED.
+ *
* \li The 'now' field is ignored if 'db' is a zone database. If 'db' is
* a cache database, then the added rdataset will expire no later than
* now + rdataset->ttl.
*
* \li #ISC_R_SUCCESS
* \li #DNS_R_UNCHANGED The operation did not change anything.
- * \li #DNS_R_NOTEXACT
+ * \li #DNS_R_NOTEXACT The TTL didn't match and #DNS_DBADD_EXACTTTL
+ * was set, or there was a partial overlap
+ * between the old and new rdatasets and
+ * #DNS_DBADD_EXACT was set.
*
* \li Other results are possible, depending upon the database
* implementation used.
bindrdataset(qpdb, qpnode, header, now, nlocktype,
tlocktype,
addedrdataset DNS__DB_FLARG_PASS);
+ if (ACTIVE(header, now) &&
+ (options & DNS_DBADD_EQUALOK) != 0 &&
+ dns_rdataslab_equalx(
+ header, newheader, qpdb->common.rdclass,
+ DNS_TYPEPAIR_TYPE(header->typepair)))
+ {
+ /*
+ * Updated by caller to ISC_R_SUCCESS after
+ * cleaning up newheader.
+ */
+ return ISC_R_EXISTS;
+ }
return DNS_R_UNCHANGED;
}
bindrdataset(qpdb, qpnode, header, now, nlocktype,
tlocktype,
addedrdataset DNS__DB_FLARG_PASS);
+ if ((options & DNS_DBADD_EQUALOK) != 0) {
+ /*
+ * Updated by caller to ISC_R_SUCCESS after
+ * cleaning up newheader.
+ */
+ return ISC_R_EXISTS;
+ }
return DNS_R_UNCHANGED;
}
bindrdataset(qpdb, qpnode, header, now, nlocktype,
tlocktype,
addedrdataset DNS__DB_FLARG_PASS);
+ if ((options & DNS_DBADD_EQUALOK) != 0) {
+ /*
+ * Updated by caller to ISC_R_SUCCESS after
+ * cleaning up newheader.
+ */
+ return ISC_R_EXISTS;
+ }
return DNS_R_UNCHANGED;
}
NODE_UNLOCK(nlock, &nlocktype);
+ if (result == ISC_R_EXISTS) {
+ result = ISC_R_SUCCESS;
+ }
+
if (tlocktype != isc_rwlocktype_none) {
TREE_UNLOCK(&qpdb->tree_lock, &tlocktype);
}
dns_dbnode_t **nodep, dns_rdataset_t *added,
dns_rdataset_t *addedsig, bool need_validation) {
isc_result_t result = ISC_R_SUCCESS;
- unsigned int options = 0;
+ unsigned int options = 0, equalok = 0;
dns_dbnode_t *node = NULL;
if (rdataset == NULL) {
options = DNS_DBADD_PREFETCH;
}
+ /*
+ * If we're validating and passing the added rdataset back to the
+ * caller, then we ask dns_db_addrdataset() to compare the old and
+ * new rdatasets whenever the result would normally have been
+ * DNS_R_UNCHANGED, and to return ISC_R_SUCCESS if they compare
+ * equal. This allows us to continue and cache RRSIGs in that case.
+ */
+ if (!need_validation && added != NULL) {
+ equalok = DNS_DBADD_EQUALOK;
+ }
+
/*
* If the node pointer points to a node, attach to it.
*
if (result == ISC_R_SUCCESS) {
result = dns_db_addrdataset(fctx->cache, node, NULL, now,
- rdataset, options, added);
+ rdataset, options | equalok, added);
}
- if (result == DNS_R_UNCHANGED) {
- /*
- * The cache wasn't updated because something was
- * already there. If the data was the same as what
- * we were trying to add, then sigrdataset might
- * still be useful.
- */
- if (!need_validation && added != NULL &&
- !dns_rdataset_equals(rdataset, added))
- {
- /* Skip adding the sigrdataset */
- } else {
- /* Carry on caching the sigrdataset */
- result = ISC_R_SUCCESS;
- }
+ if (equalok == 0 && result == DNS_R_UNCHANGED) {
+ result = ISC_R_SUCCESS;
}
if (result == ISC_R_SUCCESS && sigrdataset != NULL) {
result = dns_db_addrdataset(fctx->cache, node, NULL, now,
sigrdataset, options, addedsig);
if (result != ISC_R_SUCCESS && result != DNS_R_UNCHANGED) {
- dns__rdataset_disassociate(added);
+ if (added != NULL) {
+ dns__rdataset_disassociate(added);
+ }
}
}