* then the caller must be holding at least one lock.
*/
static void
-newref(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t nlocktype,
- isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
- uint_fast32_t refs;
-
- qpcnode_ref(node);
- refs = isc_refcount_increment0(&node->erefs);
+qpcnode_newref(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t nlocktype,
+ isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
+ uint_fast32_t refs = isc_refcount_increment0(&node->erefs);
#if DNS_DB_NODETRACE
fprintf(stderr, "incr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
}
}
+static void
+newref(qpcache_t *qpdb, qpcnode_t *node, isc_rwlocktype_t nlocktype,
+ isc_rwlocktype_t tlocktype DNS__DB_FLARG) {
+ qpcnode_ref(node);
+ qpcnode_newref(qpdb, node, nlocktype, tlocktype DNS__DB_FLARG_PASS);
+}
+
static void
cleanup_deadnodes(void *arg);
isc_result_t result;
bool locked = *tlocktypep != isc_rwlocktype_none;
bool write_locked = false;
- db_nodelock_t *nodelock = NULL;
int bucket = node->locknum;
+ db_nodelock_t *nodelock = &qpdb->node_locks[bucket];
uint_fast32_t refs;
REQUIRE(*nlocktypep != isc_rwlocktype_none);
- nodelock = &qpdb->node_locks[bucket];
-
-#define KEEP_NODE(n, r) ((n)->data != NULL || (n) == (r)->origin_node)
-
- /* Handle easy and typical case first. */
- if (!node->dirty && KEEP_NODE(node, qpdb)) {
- bool no_reference = false;
-
- refs = isc_refcount_decrement(&node->erefs);
+ refs = isc_refcount_decrement(&node->erefs);
#if DNS_DB_NODETRACE
- fprintf(stderr,
- "decr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
- func, file, line, node, refs - 1);
-#else
- UNUSED(refs);
+ fprintf(stderr, "decr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
+ func, file, line, node, refs - 1);
#endif
- if (refs == 1) {
- refs = isc_refcount_decrement(&nodelock->references);
+ if (refs > 1) {
+ qpcnode_unref(node);
+ return false;
+ }
+
+ refs = isc_refcount_decrement(&nodelock->references);
#if DNS_DB_NODETRACE
- fprintf(stderr,
- "decr:nodelock:%s:%s:%u:%p:%p->references = "
- "%" PRIuFAST32 "\n",
- func, file, line, node, nodelock, refs - 1);
+ fprintf(stderr,
+ "decr:nodelock:%s:%s:%u:%p:%p->references = "
+ "%" PRIuFAST32 "\n",
+ func, file, line, node, nodelock, refs - 1);
#else
- UNUSED(refs);
+ UNUSED(refs);
#endif
- no_reference = true;
- }
+ /* Handle easy and typical case first. */
+ if (!node->dirty && (node->data != NULL || node == qpdb->origin_node)) {
qpcnode_unref(node);
- return no_reference;
+ return false;
}
+ /*
+ * 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.
+ */
+ qpcnode_newref(qpdb, node, *nlocktypep, *tlocktypep DNS__DB_FLARG_PASS);
+
/* Upgrade the lock? */
if (*nlocktypep == isc_rwlocktype_read) {
NODE_FORCEUPGRADE(&nodelock->lock, nlocktypep);
return false;
}
- INSIST(refs == 1);
-
if (node->dirty) {
clean_cache_node(qpdb, node);
}
UNUSED(refs);
#endif
- if (KEEP_NODE(node, qpdb)) {
+ if (node->data != NULL || node == qpdb->origin_node) {
goto restore_locks;
}
}
static void
-newref(qpzonedb_t *qpdb, qpznode_t *node DNS__DB_FLARG) {
- uint_fast32_t refs;
-
- qpznode_ref(node);
- refs = isc_refcount_increment0(&node->erefs);
+qpznode_newref(qpzonedb_t *qpdb, qpznode_t *node DNS__DB_FLARG) {
+ uint_fast32_t refs = isc_refcount_increment0(&node->erefs);
#if DNS_DB_NODETRACE
fprintf(stderr, "incr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
func, file, line, node, refs + 1);
-#else
- UNUSED(refs);
#endif
if (refs == 0) {
}
}
+static void
+newref(qpzonedb_t *qpdb, qpznode_t *node DNS__DB_FLARG) {
+ qpznode_ref(node);
+ qpznode_newref(qpdb, node DNS__DB_FLARG_PASS);
+}
+
static void
clean_zone_node(qpznode_t *node, uint32_t least_serial) {
dns_slabheader_t *current = NULL, *dcurrent = NULL;
static void
decref(qpzonedb_t *qpdb, qpznode_t *node, uint32_t least_serial,
isc_rwlocktype_t *nlocktypep DNS__DB_FLARG) {
- db_nodelock_t *nodelock = NULL;
int bucket = node->locknum;
+ db_nodelock_t *nodelock = &qpdb->node_locks[bucket];
uint_fast32_t refs;
REQUIRE(*nlocktypep != isc_rwlocktype_none);
- nodelock = &qpdb->node_locks[bucket];
-
- /* Handle easy and typical case first. */
- if (!node->dirty && (node->data != NULL || node == qpdb->origin ||
- node == qpdb->nsec3_origin))
- {
- refs = isc_refcount_decrement(&node->erefs);
+ refs = isc_refcount_decrement(&node->erefs);
#if DNS_DB_NODETRACE
- fprintf(stderr,
- "decr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
- func, file, line, node, refs - 1);
-#else
- UNUSED(refs);
+ fprintf(stderr, "decr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
+ func, file, line, node, refs - 1);
#endif
- if (refs == 1) {
- refs = isc_refcount_decrement(&nodelock->references);
+ if (refs > 1) {
+ qpznode_unref(node);
+ return;
+ }
+
+ refs = isc_refcount_decrement(&nodelock->references);
#if DNS_DB_NODETRACE
- fprintf(stderr,
- "decr:nodelock:%s:%s:%u:%p:%p->references = "
- "%" PRIuFAST32 "\n",
- func, file, line, node, nodelock, refs - 1);
+ fprintf(stderr,
+ "decr:nodelock:%s:%s:%u:%p:%p->references = "
+ "%" PRIuFAST32 "\n",
+ func, file, line, node, nodelock, refs - 1);
#else
- UNUSED(refs);
+ UNUSED(refs);
#endif
- }
- goto done;
+
+ /* Handle easy and typical case first. */
+ if (!node->dirty && (node->data != NULL || node == qpdb->origin ||
+ node == qpdb->nsec3_origin))
+ {
+ qpznode_unref(node);
+ return;
}
+ /*
+ * 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.
+ */
+ qpznode_newref(qpdb, node DNS__DB_FLARG_PASS);
+
/* Upgrade the lock? */
if (*nlocktypep == isc_rwlocktype_read) {
NODE_FORCEUPGRADE(&nodelock->lock, nlocktypep);
fprintf(stderr, "decr:node:%s:%s:%u:%p->erefs = %" PRIuFAST32 "\n",
func, file, line, node, refs - 1);
#endif
- if (refs == 1) {
- if (node->dirty) {
- if (least_serial == 0) {
- /*
- * Caller doesn't know the least serial.
- * Get it.
- */
- RWLOCK(&qpdb->lock, isc_rwlocktype_read);
- least_serial = qpdb->least_serial;
- RWUNLOCK(&qpdb->lock, isc_rwlocktype_read);
- }
- clean_zone_node(node, least_serial);
+ if (refs > 1) {
+ qpznode_unref(node);
+ return;
+ }
+
+ if (node->dirty) {
+ if (least_serial == 0) {
+ /*
+ * Caller doesn't know the least serial.
+ * Get it.
+ */
+ RWLOCK(&qpdb->lock, isc_rwlocktype_read);
+ least_serial = qpdb->least_serial;
+ RWUNLOCK(&qpdb->lock, isc_rwlocktype_read);
}
+ clean_zone_node(node, least_serial);
+ }
- refs = isc_refcount_decrement(&nodelock->references);
+ refs = isc_refcount_decrement(&nodelock->references);
#if DNS_DB_NODETRACE
- fprintf(stderr,
- "decr:nodelock:%s:%s:%u:%p:%p->references = "
- "%" PRIuFAST32 "\n",
- func, file, line, node, nodelock, refs - 1);
+ fprintf(stderr,
+ "decr:nodelock:%s:%s:%u:%p:%p->references = "
+ "%" PRIuFAST32 "\n",
+ func, file, line, node, nodelock, refs - 1);
#else
- UNUSED(refs);
+ UNUSED(refs);
#endif
- }
-done:
qpznode_unref(node);
}