grep "ANSWER: 1" dig.ns7.out.${n} > /dev/null || ret=1
if [ $ret != 0 ]; then echo "I:failed"; ret=1; fi
status=`expr $status + $ret`
-#HERE >>>
n=`expr $n + 1`
echo "I:check that '-t aaaa' in .digrc does not have unexpected side effects ($n)"
if [ $ret != 0 ]; then echo "I:failed"; fi
status=`expr $status + $ret`
+n=`expr $n + 1`
+echo "I:check zero ttl not returned for learnt non zero ttl records (${n})"
+ret=0
+# use prefetch disabled server
+$DIG @10.53.0.7 -p 5300 non-zero.example.net txt > dig.out.1.${n} || ret=1
+ttl1=`awk '/"A" "short" "ttl"/ { print $2 - 2 }' dig.out.1.${n}`
+# sleep so we are in expire range
+sleep ${ttl1:-0}
+# look for ttl = 1, allow for one miss at getting zero ttl
+zerotonine="0 1 2 3 4 5 6 7 8 9"
+zerotonine="$zerotonine $zerotonine $zerotonine"
+for i in $zerotonine $zerotonine $zerotonine $zerotonine
+do
+ $DIG @10.53.0.7 -p 5300 non-zero.example.net txt > dig.out.2.${n} || ret=1
+ ttl2=`awk '/"A" "short" "ttl"/ { print $2 }' dig.out.2.${n}`
+ test ${ttl2:-1} -eq 0 && break
+ test ${ttl2:-1} -ge ${ttl1:-0} && break
+ $PERL -e 'select(undef, undef, undef, 0.05);'
+done
+test ${ttl2:-1} -eq 0 && ret=1
+test ${ttl2:-1} -ge ${ttl1:-0} || break
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
+
+n=`expr $n + 1`
+echo "I:check zero ttl is returned for learnt zero ttl records (${n})"
+ret=0
+$DIG @10.53.0.7 -p 5300 zero.example.net txt > dig.out.1.${n} || ret=1
+ttl=`awk '/"A" "zero" "ttl"/ { print $2 }' dig.out.1.${n}`
+test ${ttl:-1} -eq 0 || ret=1
+if [ $ret != 0 ]; then echo "I:failed"; fi
+status=`expr $status + $ret`
echo "I:exit status: $status"
exit $status
#define RDATASET_ATTR_STATCOUNT 0x0040
#define RDATASET_ATTR_OPTOUT 0x0080
#define RDATASET_ATTR_NEGATIVE 0x0100
+#define RDATASET_ATTR_PREFETCH 0x0200
+#define RDATASET_ATTR_CASESET 0x0400
+#define RDATASET_ATTR_ZEROTTL 0x0800
typedef struct acache_cbarg {
dns_rdatasetadditional_t type;
(((header)->attributes & RDATASET_ATTR_OPTOUT) != 0)
#define NEGATIVE(header) \
(((header)->attributes & RDATASET_ATTR_NEGATIVE) != 0)
+#define PREFETCH(header) \
+ (((header)->attributes & RDATASET_ATTR_PREFETCH) != 0)
+#define CASESET(header) \
+ (((header)->attributes & RDATASET_ATTR_CASESET) != 0)
+#define ZEROTTL(header) \
+ (((header)->attributes & RDATASET_ATTR_ZEROTTL) != 0)
#define DEFAULT_NODE_LOCK_COUNT 7 /*%< Should be prime. */
header_prev = NULL;
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
- if (header->rdh_ttl < search->now) {
+ if (header->rdh_ttl < search->now ||
+ (header->rdh_ttl == search->now && !ZEROTTL(header))) {
/*
* This rdataset is stale. If no one else is
* using the node, we can clean it up right
* the node as dirty, so it will get cleaned
* up later.
*/
- if ((header->rdh_ttl < search->now - RBTDB_VIRTUAL) &&
+ if ((header->rdh_ttl < search->now - RBTDB_VIRTUAL) &&
(locktype == isc_rwlocktype_write ||
NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
/*
header != NULL;
header = header_next) {
header_next = header->next;
- if (header->rdh_ttl < search->now) {
+ if (header->rdh_ttl < search->now ||
+ (header->rdh_ttl == search->now && !ZEROTTL(header))) {
/*
* This rdataset is stale. If no one else is
* using the node, we can clean it up right
* the node as dirty, so it will get cleaned
* up later.
*/
- if ((header->rdh_ttl < search->now -
+ if ((header->rdh_ttl < search->now -
RBTDB_VIRTUAL) &&
(locktype == isc_rwlocktype_write ||
NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
header != NULL;
header = header_next) {
header_next = header->next;
- if (header->rdh_ttl < now) {
+ if (header->rdh_ttl < now ||
+ (header->rdh_ttl == now && !ZEROTTL(header))) {
/*
* This rdataset is stale. If no one else is
* using the node, we can clean it up right
* node as dirty, so it will get cleaned up
* later.
*/
- if ((header->rdh_ttl < now - RBTDB_VIRTUAL) &&
+ if ((header->rdh_ttl < now - RBTDB_VIRTUAL) &&
(locktype == isc_rwlocktype_write ||
NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
/*
header_prev = NULL;
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
- if (header->rdh_ttl < now) {
+ if (header->rdh_ttl < now ||
+ (header->rdh_ttl == now && !ZEROTTL(header))) {
/*
* This rdataset is stale. If no one else is using the
* node, we can clean it up right now, otherwise we
* mark it as stale, and the node as dirty, so it will
* get cleaned up later.
*/
- if ((header->rdh_ttl < now - RBTDB_VIRTUAL) &&
+ if ((header->rdh_ttl < now - RBTDB_VIRTUAL) &&
(locktype == isc_rwlocktype_write ||
NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
/*
header_prev = NULL;
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
- if (header->rdh_ttl < now) {
+ if (header->rdh_ttl < now ||
+ (header->rdh_ttl == now && !ZEROTTL(header))) {
/*
* This rdataset is stale. If no one else is using the
* node, we can clean it up right now, otherwise we
for (header = rbtnode->data; header != NULL; header = header_next) {
header_next = header->next;
- if (header->rdh_ttl < now) {
+ if (header->rdh_ttl < now ||
+ (header->rdh_ttl == now && !ZEROTTL(header))) {
if ((header->rdh_ttl < now - RBTDB_VIRTUAL) &&
(locktype == isc_rwlocktype_write ||
NODE_TRYUPGRADE(lock) == ISC_R_SUCCESS)) {
newheader->type = RBTDB_RDATATYPE_VALUE(rdataset->type,
rdataset->covers);
newheader->attributes = 0;
+ if (rdataset->ttl == 0U)
+ newheader->attributes |= RDATASET_ATTR_ZEROTTL;
newheader->noqname = NULL;
newheader->closest = NULL;
newheader->count = init_count++;