free_adbfetch(dns_adb_t *, dns_adbfetch_t **);
static void
purge_stale_names(dns_adb_t *adb, isc_stdtime_t now);
+static void
+purge_names_overmem(dns_adb_t *adb, size_t requested);
static dns_adbname_t *
get_attached_and_locked_name(dns_adb_t *, const dns_name_t *, unsigned int type,
isc_stdtime_t now);
static void
purge_stale_entries(dns_adb_t *adb, isc_stdtime_t now);
+static void
+purge_entries_overmem(dns_adb_t *adb, size_t requested);
static dns_adbentry_t *
get_attached_and_locked_entry(dns_adb_t *adb, isc_stdtime_t now,
const isc_sockaddr_t *addr);
clean_finds_at_name(dns_adbname_t *, dns_adbstatus_t, unsigned int);
static void
maybe_expire_namehooks(dns_adbname_t *, isc_stdtime_t);
-static bool
+static void
maybe_expire_name(dns_adbname_t *adbname, isc_stdtime_t now);
static void
expire_name(dns_adbname_t *adbname, dns_adbstatus_t astat);
};
uint32_t hashval = hash_adbname(&key);
isc_rwlocktype_t locktype = isc_rwlocktype_read;
+ bool overmem = isc_mem_isovermem(adb->mctx);
isc_time_set(&timenow, now, 0);
RWLOCK(&adb->names_lock, locktype);
last_update = adb->names_last_update;
- if (last_update + ADB_STALE_MARGIN >= now ||
- isc_mem_isovermem(adb->mctx))
- {
+ if (last_update + ADB_STALE_MARGIN >= now || overmem) {
last_update = now;
UPGRADELOCK(&adb->names_lock, locktype);
- purge_stale_names(adb, now);
+ if (overmem) {
+ purge_names_overmem(adb, 2 * sizeof(*adbname));
+ } else {
+ purge_stale_names(adb, now);
+ }
adb->names_last_update = last_update;
}
return adbname;
}
-static void
-upgrade_entries_lock(dns_adb_t *adb, isc_rwlocktype_t *locktypep,
- isc_stdtime_t now) {
- if (*locktypep == isc_rwlocktype_read) {
- UPGRADELOCK(&adb->entries_lock, *locktypep);
- purge_stale_entries(adb, now);
- adb->entries_last_update = now;
- }
-}
-
static bool
match_adbentry(void *node, const void *key) {
dns_adbentry_t *adbentry = node;
isc_stdtime_t last_update;
uint32_t hashval = isc_sockaddr_hash(addr, true);
isc_rwlocktype_t locktype = isc_rwlocktype_read;
+ bool overmem = isc_mem_isovermem(adb->mctx);
isc_time_set(&timenow, now, 0);
RWLOCK(&adb->entries_lock, locktype);
last_update = adb->entries_last_update;
- if (now - last_update > ADB_STALE_MARGIN ||
- isc_mem_isovermem(adb->mctx))
- {
+ if (now - last_update > ADB_STALE_MARGIN || overmem) {
last_update = now;
- upgrade_entries_lock(adb, &locktype, now);
+ UPGRADELOCK(&adb->entries_lock, locktype);
+ if (overmem) {
+ purge_entries_overmem(adb, 2 * sizeof(*adbentry));
+ } else {
+ purge_stale_entries(adb, now);
+ }
+ adb->entries_last_update = now;
}
result = isc_hashmap_find(adb->entries, hashval, match_adbentry,
(const unsigned char *)addr,
(void **)&adbentry);
if (result == ISC_R_NOTFOUND) {
- upgrade_entries_lock(adb, &locktype, now);
+ UPGRADELOCK(&adb->entries_lock, locktype);
create:
INSIST(locktype == isc_rwlocktype_write);
/* We need to upgrade the LRU lock */
UNLOCK(&adbentry->lock);
- upgrade_entries_lock(adb, &locktype, now);
+ UPGRADELOCK(&adb->entries_lock, locktype);
LOCK(&adbentry->lock);
FALLTHROUGH;
case isc_rwlocktype_write:
/*
* The name must be locked and write lock on adb->names_lock must be held.
*/
-static bool
+static void
maybe_expire_name(dns_adbname_t *adbname, isc_stdtime_t now) {
REQUIRE(DNS_ADBNAME_VALID(adbname));
/* Leave this name alone if it still has active namehooks... */
if (NAME_HAS_V4(adbname) || NAME_HAS_V6(adbname)) {
- return false;
+ return;
}
/* ...an active fetch in progres... */
if (NAME_FETCH(adbname)) {
- return false;
+ return;
}
/* ... or is not yet expired. */
if (!EXPIRE_OK(adbname->expire_v4, now) ||
!EXPIRE_OK(adbname->expire_v6, now))
{
- return false;
+ return;
}
expire_name(adbname, DNS_ADB_EXPIRED);
-
- return true;
}
static void
*/
static void
purge_stale_names(dns_adb_t *adb, isc_stdtime_t now) {
- bool overmem = isc_mem_isovermem(adb->mctx);
- int max_removed = overmem ? 2 : 1;
- int scans = 0, removed = 0;
- dns_adbname_t *prev = NULL;
+ dns_adbname_t *adbname = ISC_LIST_TAIL(adb->names_lru);
+
+ if (adbname == NULL) {
+ return;
+ }
+
+ dns_adbname_ref(adbname);
+ LOCK(&adbname->lock);
/*
- * We limit the number of scanned entries to 10 (arbitrary choice)
- * in order to avoid examining too many entries when there are many
- * tail entries that have fetches (this should be rare, but could
- * happen).
+ * Remove the name if it's expired or unused, has no address data.
*/
+ maybe_expire_namehooks(adbname, now);
+ maybe_expire_name(adbname, now);
+
+ UNLOCK(&adbname->lock);
+ dns_adbname_detach(&adbname);
+}
+
+static void
+purge_names_overmem(dns_adb_t *adb, size_t requested) {
+ dns_adbname_t *prev = NULL;
+ size_t expired = 0;
for (dns_adbname_t *adbname = ISC_LIST_TAIL(adb->names_lru);
- adbname != NULL && removed < max_removed && scans < 10;
- adbname = prev)
+ adbname != NULL && expired < requested; adbname = prev)
{
prev = ISC_LIST_PREV(adbname, link);
dns_adbname_ref(adbname);
LOCK(&adbname->lock);
- scans++;
-
/*
* Remove the name if it's expired or unused,
* has no address data.
*/
- maybe_expire_namehooks(adbname, now);
- if (maybe_expire_name(adbname, now)) {
- removed++;
- goto next;
- }
-
- /*
- * Make sure that we are not purging ADB names that has been
- * just created.
- */
- if (adbname->last_used + ADB_CACHE_MINIMUM >= now) {
- prev = NULL;
- goto next;
- }
-
- if (overmem) {
- expire_name(adbname, DNS_ADB_CANCELED);
- removed++;
- goto next;
- }
-
- if (adbname->last_used + ADB_STALE_MARGIN < now) {
- expire_name(adbname, DNS_ADB_CANCELED);
- removed++;
- goto next;
- }
-
- /*
- * We won't expire anything on the LRU list as the
- * .last_used + ADB_STALE_MARGIN will always be bigger
- * than `now` for all previous entries, so we just stop
- * the scanning.
- */
- prev = NULL;
- next:
+ maybe_expire_namehooks(adbname, INT_MAX);
+ expire_name(adbname, DNS_ADB_CANCELED);
+ expired += sizeof(*adbname);
UNLOCK(&adbname->lock);
dns_adbname_detach(&adbname);
}
* fetches, we can remove this name from the bucket.
*/
maybe_expire_namehooks(adbname, now);
- (void)maybe_expire_name(adbname, now);
+ maybe_expire_name(adbname, now);
UNLOCK(&adbname->lock);
dns_adbname_detach(&adbname);
}
*/
static void
purge_stale_entries(dns_adb_t *adb, isc_stdtime_t now) {
- bool overmem = isc_mem_isovermem(adb->mctx);
- int max_removed = overmem ? 2 : 1;
- int scans = 0, removed = 0;
+ dns_adbentry_t *adbentry = ISC_LIST_TAIL(adb->entries_lru);
+
+ if (adbentry == NULL) {
+ return;
+ }
+
+ dns_adbentry_ref(adbentry);
+ LOCK(&adbentry->lock);
+
+ /*
+ * Remove the entry if it's expired and unused.
+ */
+ (void)maybe_expire_entry(adbentry, now);
+
+ UNLOCK(&adbentry->lock);
+ dns_adbentry_detach(&adbentry);
+}
+
+static void
+purge_entries_overmem(dns_adb_t *adb, size_t requested) {
dns_adbentry_t *prev = NULL;
+ size_t expired = 0;
/*
* We limit the number of scanned entries to 10 (arbitrary choice)
*/
for (dns_adbentry_t *adbentry = ISC_LIST_TAIL(adb->entries_lru);
- adbentry != NULL && removed < max_removed && scans < 10;
- adbentry = prev)
+ adbentry != NULL && expired < requested; adbentry = prev)
{
prev = ISC_LIST_PREV(adbentry, link);
dns_adbentry_ref(adbentry);
LOCK(&adbentry->lock);
- scans++;
-
- /*
- * Remove the entry if it's expired and unused.
- */
- if (maybe_expire_entry(adbentry, now)) {
- removed++;
- goto next;
- }
-
- /*
- * Make sure that we are not purging ADB entry that has been
- * just created.
- */
- if (adbentry->last_used + ADB_CACHE_MINIMUM >= now) {
- prev = NULL;
- goto next;
- }
-
- if (overmem) {
- maybe_expire_entry(adbentry, INT_MAX);
- removed++;
- goto next;
- }
-
- if (adbentry->last_used + ADB_STALE_MARGIN < now) {
- maybe_expire_entry(adbentry, INT_MAX);
- removed++;
- goto next;
- }
+ (void)maybe_expire_entry(adbentry, INT_MAX);
+ expired += sizeof(*adbentry);
- /*
- * We won't expire anything on the LRU list as the
- * .last_used + ADB_STALE_MARGIN will always be bigger
- * than `now` for all previous entries, so we just stop
- * the scanning
- */
- prev = NULL;
- next:
UNLOCK(&adbentry->lock);
dns_adbentry_detach(&adbentry);
}