Previously, rbtdb->task had quantum of 1 because it was originally used
just for freeing RBTDB contents, which can happen on a "best effort"
basis (does not need to be prioritized). However, when tree pruning was
implemented, it also started sending events to that task, enabling the
latter to become clogged up with a significant event backlog because it
only pruned a single RBTDB node per event.
To prioritize tree pruning (as it is necessary for enforcing the
configured memory use limit for the cache memory context), create a
second task with a virtually unlimited quantum (UINT_MAX) and send the
tree-pruning events to this new task, to ensure that all nodes scheduled
for pruning will be processed before further nodes are queued in a
similar fashion.
This change enables dropping the prunenodes list and restoring the
originally-used logic that allocates and sends a separate event for each
node to prune.
(cherry picked from commit
231b2375e5b9b98096711f5e883911134adb6392)
}
static void
-settask(dns_db_t *db, isc_task_t *task) {
+settask(dns_db_t *db, isc_task_t *task, isc_task_t *prunetask) {
sampledb_t *sampledb = (sampledb_t *)db;
REQUIRE(VALID_SAMPLEDB(sampledb));
- dns_db_settask(sampledb->rbtdb, task);
+ dns_db_settask(sampledb->rbtdb, task, prunetask);
}
static isc_result_t
isc_result_t result;
dns_cache_t *cache;
int i, extra = 0;
- isc_task_t *dbtask;
REQUIRE(cachep != NULL);
REQUIRE(*cachep == NULL);
goto cleanup_dbargv;
}
if (taskmgr != NULL) {
- dbtask = NULL;
+ isc_task_t *dbtask = NULL;
+ isc_task_t *prunetask = NULL;
+
result = isc_task_create(taskmgr, 1, &dbtask);
if (result != ISC_R_SUCCESS) {
goto cleanup_db;
}
-
isc_task_setname(dbtask, "cache_dbtask", NULL);
- dns_db_settask(cache->db, dbtask);
+
+ result = isc_task_create(taskmgr, UINT_MAX, &prunetask);
+ if (result != ISC_R_SUCCESS) {
+ isc_task_detach(&dbtask);
+ goto cleanup_db;
+ }
+ isc_task_setname(prunetask, "cache_prunetask", NULL);
+
+ dns_db_settask(cache->db, dbtask, prunetask);
isc_task_detach(&dbtask);
+ isc_task_detach(&prunetask);
}
cache->magic = CACHE_MAGIC;
}
void
-dns_db_settask(dns_db_t *db, isc_task_t *task) {
+dns_db_settask(dns_db_t *db, isc_task_t *task, isc_task_t *prunetask) {
REQUIRE(DNS_DB_VALID(db));
- (db->methods->settask)(db, task);
+ (db->methods->settask)(db, task, prunetask);
}
isc_result_t
unsigned int (*nodecount)(dns_db_t *db, dns_dbtree_t);
bool (*ispersistent)(dns_db_t *db);
void (*overmem)(dns_db_t *db, bool overmem);
- void (*settask)(dns_db_t *db, isc_task_t *);
+ void (*settask)(dns_db_t *db, isc_task_t *, isc_task_t *);
isc_result_t (*getoriginnode)(dns_db_t *db, dns_dbnode_t **nodep);
void (*transfernode)(dns_db_t *db, dns_dbnode_t **sourcep,
dns_dbnode_t **targetp);
*/
void
-dns_db_settask(dns_db_t *db, isc_task_t *task);
+dns_db_settask(dns_db_t *db, isc_task_t *task, isc_task_t *prunetask);
/*%<
* If task is set then the final detach maybe performed asynchronously.
*
* Requires:
* \li 'db' is a valid database.
- * \li 'task' to be valid or NULL.
+ * \li 'task' to be valid or NULL (default task to send events to).
+ * \li 'prunetask' to be valid or NULL (task to send tree-pruning events to).
*/
bool
rbtdb_version_t *future_version;
rbtdb_versionlist_t open_versions;
isc_task_t *task;
+ isc_task_t *prunetask;
dns_dbnode_t *soanode;
dns_dbnode_t *nsnode;
if (rbtdb->task != NULL) {
isc_task_detach(&rbtdb->task);
}
+ if (rbtdb->prunetask != NULL) {
+ isc_task_detach(&rbtdb->prunetask);
+ }
RBTDB_DESTROYLOCK(&rbtdb->lock);
rbtdb->common.magic = 0;
db = NULL;
attach((dns_db_t *)rbtdb, &db);
ev->ev_sender = db;
- isc_task_send(rbtdb->task, &ev);
+ isc_task_send(rbtdb->prunetask, &ev);
}
/*%
}
static void
-settask(dns_db_t *db, isc_task_t *task) {
+settask(dns_db_t *db, isc_task_t *task, isc_task_t *prunetask) {
dns_rbtdb_t *rbtdb;
rbtdb = (dns_rbtdb_t *)db;
if (task != NULL) {
isc_task_attach(task, &rbtdb->task);
}
+ if (rbtdb->prunetask != NULL) {
+ isc_task_detach(&rbtdb->prunetask);
+ }
+ if (prunetask != NULL) {
+ isc_task_attach(prunetask, &rbtdb->prunetask);
+ }
RBTDB_UNLOCK(&rbtdb->lock, isc_rwlocktype_write);
}
isc_refcount_init(&rbtdb->references, 1);
rbtdb->attributes = 0;
rbtdb->task = NULL;
+ rbtdb->prunetask = NULL;
rbtdb->serve_stale_ttl = 0;
/*
}
static void
-settask(dns_db_t *db, isc_task_t *task) {
+settask(dns_db_t *db, isc_task_t *task, isc_task_t *prunetask) {
UNUSED(db);
UNUSED(task);
+ UNUSED(prunetask);
}
static dns_dbmethods_t sdb_methods = {
}
static void
-settask(dns_db_t *db, isc_task_t *task) {
+settask(dns_db_t *db, isc_task_t *task, isc_task_t *prunetask) {
UNUSED(db);
UNUSED(task);
+ UNUSED(prunetask);
}
/*
isc_result_totext(result));
goto cleanup;
}
- dns_db_settask(db, zone->task);
+ dns_db_settask(db, zone->task, zone->task);
if (zone->type == dns_zone_primary ||
zone->type == dns_zone_secondary || zone->type == dns_zone_mirror)
isc_result_totext(result));
goto cleanup;
}
- dns_db_settask(stub->db, zone->task);
+ dns_db_settask(stub->db, zone->task, zone->task);
}
result = dns_db_newversion(stub->db, &stub->version);
isc_task_attach(task, &zone->task);
ZONEDB_LOCK(&zone->dblock, isc_rwlocktype_read);
if (zone->db != NULL) {
- dns_db_settask(zone->db, zone->task);
+ dns_db_settask(zone->db, zone->task, zone->task);
}
ZONEDB_UNLOCK(&zone->dblock, isc_rwlocktype_read);
UNLOCK_ZONE(zone);
zone_detachdb(zone);
}
zone_attachdb(zone, db);
- dns_db_settask(zone->db, zone->task);
+ dns_db_settask(zone->db, zone->task, zone->task);
DNS_ZONE_SETFLAG(zone, DNS_ZONEFLG_LOADED | DNS_ZONEFLG_NEEDNOTIFY);
return (ISC_R_SUCCESS);