mirror of
https://github.com/isc-projects/bind9.git
synced 2026-05-27 20:25:55 -04:00
Optimize database decref by avoiding locking with refs > 1
Previously, this function always acquires a node write lock if it
might need node cleanup in case the reference decrements to 0. In
fact, the lock is unnecessary if the reference is larger than 1 and it
can be optimized as an "easy" case. This optimization could even be
"necessary". In some extreme cases, many worker threads could repeat
acquring and releasing the reference on the same node, resulting in
severe lock contention for nothing (as the ref wouldn't decrement to 0
in most cases). This change would prevent noticeable performance
drop like query timeout for such cases.
Co-authored-by: JINMEI Tatuya <jtatuya@infoblox.com>
Co-authored-by: Ondřej Surý <ondrej@isc.org>
(cherry picked from commit 7f4471594d)
This commit is contained in:
parent
57187b2c4f
commit
065ffb2eb8
1 changed files with 17 additions and 10 deletions
|
|
@ -2046,28 +2046,35 @@ decrement_reference(dns_rbtdb_t *rbtdb, dns_rbtnode_t *node,
|
|||
isc_result_t result;
|
||||
bool write_locked;
|
||||
bool locked = tlock != isc_rwlocktype_none;
|
||||
rbtdb_nodelock_t *nodelock;
|
||||
int bucket = node->locknum;
|
||||
rbtdb_nodelock_t *nodelock = &rbtdb->node_locks[bucket];
|
||||
bool no_reference = true;
|
||||
uint_fast32_t refs;
|
||||
|
||||
nodelock = &rbtdb->node_locks[bucket];
|
||||
|
||||
#define KEEP_NODE(n, r, l) \
|
||||
((n)->data != NULL || ((l) && (n)->down != NULL) || \
|
||||
(n) == (r)->origin_node || (n) == (r)->nsec3_origin_node)
|
||||
|
||||
/* Handle easy and/or typical case first. */
|
||||
if (isc_refcount_decrement(&node->references) > 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
refs = isc_refcount_decrement(&nodelock->references);
|
||||
INSIST(refs > 0);
|
||||
|
||||
/* Handle easy and typical case first. */
|
||||
if (!node->dirty && KEEP_NODE(node, rbtdb, locked)) {
|
||||
if (isc_refcount_decrement(&node->references) == 1) {
|
||||
refs = isc_refcount_decrement(&nodelock->references);
|
||||
INSIST(refs > 0);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Node lock ref has decremented to 0 and we may need to clean up the
|
||||
* node. To clean it up, the node ref needs to decrement to 0 under the
|
||||
* node write lock, so we regain the ref and try again.
|
||||
*/
|
||||
new_reference(rbtdb, node, nlock);
|
||||
|
||||
/* Upgrade the lock? */
|
||||
if (nlock == isc_rwlocktype_read) {
|
||||
NODE_UNLOCK(&nodelock->lock, isc_rwlocktype_read);
|
||||
|
|
|
|||
Loading…
Reference in a new issue