#define QPDB_ATTR_LOADED 0x01
#define QPDB_ATTR_LOADING 0x02
+#ifndef DEFAULT_BUCKETS_COUNT
#define DEFAULT_BUCKETS_COUNT 17 /*%< Should be prime. */
+#endif
#define QPDBITER_NSEC3_ORIGIN_NODE(qpdb, iterator) \
((iterator)->current == &(iterator)->nsec3iter && \
typedef struct qpzonedb qpzonedb_t;
typedef struct qpznode qpznode_t;
+typedef struct qpzone_bucket {
+ /* Per-bucket lock. */
+ isc_rwlock_t lock;
+
+ /* Padding to prevent false sharing between locks. */
+ uint8_t __padding[ISC_OS_CACHELINE_SIZE -
+ (sizeof(isc_rwlock_t)) % ISC_OS_CACHELINE_SIZE];
+} qpzone_bucket_t;
+
typedef struct qpz_changed {
qpznode_t *node;
bool dirty;
void *data;
};
-typedef struct qpzone_bucket {
- /* Per-bucket lock. */
- isc_rwlock_t lock;
-
- /* Padding to prevent false sharing between locks. */
- uint8_t __padding[ISC_OS_CACHELINE_SIZE -
- (sizeof(isc_rwlock_t)) % ISC_OS_CACHELINE_SIZE];
-} qpzone_bucket_t;
-
struct qpzonedb {
/* Unlocked. */
dns_db_t common;
dns_qpmulti_t *nsec; /* NSEC nodes only */
dns_qpmulti_t *nsec3; /* NSEC3 nodes only */
- size_t buckets_count;
- qpzone_bucket_t buckets[]; /* attribute((counted_by(buckets_count))) */
+ qpzone_bucket_t buckets[DEFAULT_BUCKETS_COUNT];
};
#ifdef DNS_DB_NODETRACE
* Failure to follow this hierarchy can result in deadlock.
*/
+static isc_rwlock_t *
+qpzone_get_lock(qpzonedb_t *qpdb, qpznode_t *node) {
+ return &qpdb->buckets[node->locknum].lock;
+}
+
+static uint16_t
+qpzone_get_locknum(void) {
+ return isc_random_uniform(DEFAULT_BUCKETS_COUNT);
+}
+
/*%
* Return which RRset should be resigned sooner. If the RRsets have the
* same signing time, prefer the other RRset over the SOA RRset.
if (dns_name_dynamic(&qpdb->common.origin)) {
dns_name_free(&qpdb->common.origin, qpdb->common.mctx);
}
- for (size_t i = 0; i < qpdb->buckets_count; i++) {
+ for (size_t i = 0; i < DEFAULT_BUCKETS_COUNT; i++) {
NODE_DESTROYLOCK(&qpdb->buckets[i].lock);
}
INSIST(!cds_lfht_destroy(qpdb->common.update_listeners, NULL));
}
- isc_mem_putanddetach(&qpdb->common.mctx, qpdb,
- sizeof(*qpdb) + qpdb->buckets_count *
- sizeof(qpdb->buckets[0]));
+ isc_mem_putanddetach(&qpdb->common.mctx, qpdb, sizeof(*qpdb));
}
static void
*newdata = (qpznode_t){
.name = DNS_NAME_INITEMPTY,
.references = ISC_REFCOUNT_INITIALIZER(1),
- .locknum = isc_random_uniform(qpdb->buckets_count),
+ .locknum = qpzone_get_locknum(),
};
isc_mem_attach(qpdb->common.mctx, &newdata->mctx);
isc_result_t result;
dns_qp_t *qp = NULL;
- qpdb = isc_mem_get(mctx,
- sizeof(*qpdb) + DEFAULT_BUCKETS_COUNT *
- sizeof(qpdb->buckets[0]));
+ qpdb = isc_mem_get(mctx, sizeof(*qpdb));
*qpdb = (qpzonedb_t){
.common.origin = DNS_NAME_INITEMPTY,
.common.rdclass = rdclass,
.common.references = ISC_REFCOUNT_INITIALIZER(1),
- .buckets_count = DEFAULT_BUCKETS_COUNT,
.current_serial = 1,
.least_serial = 1,
.next_serial = 2,
isc_heap_create(mctx, resign_sooner, set_index, 0, &qpdb->heap);
- for (size_t i = 0; i < qpdb->buckets_count; i++) {
+ for (size_t i = 0; i < DEFAULT_BUCKETS_COUNT; i++) {
NODE_INITLOCK(&qpdb->buckets[i].lock);
}
* erefs_increment. If another thread acquires reference it
* will be larger than 0, if it doesn't it is going to be 0.
*/
- isc_rwlock_t *nlock = &qpdb->buckets[node->locknum].lock;
+ isc_rwlock_t *nlock = qpzone_get_lock(qpdb, node);
qpznode_erefs_increment(qpdb, node DNS__DB_FLARG_PASS);
NODE_FORCEUPGRADE(nlock, nlocktypep);
if (!qpznode_erefs_decrement(qpdb, node DNS__DB_FLARG_PASS)) {
version->havensec3 = false;
node = qpdb->origin;
- nlock = &qpdb->buckets[node->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, node);
NODE_RDLOCK(nlock, &nlocktype);
for (header = node->data; header != NULL; header = header_next) {
header_next = header->next;
ISC_LIST_UNLINK(resigned_list, header, link);
- nlock = &qpdb->buckets[HEADERNODE(header)->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, HEADERNODE(header));
NODE_WRLOCK(nlock, &nlocktype);
if (rollback && !IGNORE(header)) {
resigninsert(qpdb, header);
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
node = changed->node;
- nlock = &qpdb->buckets[node->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, node);
NODE_WRLOCK(nlock, &nlocktype);
if (rollback) {
}
serial = version->serial;
- nlock = &qpdb->buckets[node->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, node);
NODE_RDLOCK(nlock, &nlocktype);
matchtype = DNS_TYPEPAIR_VALUE(type, covers);
newheader->resign_lsb = rdataset->resign & 0x1;
}
- nlock = &qpdb->buckets[node->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, node);
NODE_WRLOCK(nlock, &nlocktype);
result = add(qpdb, node, name, qpdb->current_version, newheader,
DNS_DBADD_MERGE, true, NULL, 0 DNS__DB_FLARG_PASS);
header = dns_rdataset_getheader(rdataset);
- nlock = &qpdb->buckets[HEADERNODE(header)->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, HEADERNODE(header));
NODE_WRLOCK(nlock, &nlocktype);
oldheader = *header;
dns_slabheader_t *header = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = NULL;
- uint16_t locknum;
isc_result_t result = ISC_R_NOTFOUND;
REQUIRE(VALID_QPZONE(qpdb));
RWUNLOCK(&qpdb->lock, isc_rwlocktype_read);
return ISC_R_NOTFOUND;
}
- locknum = HEADERNODE(header)->locknum;
+ nlock = qpzone_get_lock(qpdb, HEADERNODE(header));
RWUNLOCK(&qpdb->lock, isc_rwlocktype_read);
again:
- nlock = &qpdb->buckets[locknum].lock;
-
NODE_RDLOCK(nlock, &nlocktype);
RWLOCK(&qpdb->lock, isc_rwlocktype_read);
header = isc_heap_element(qpdb->heap, 1);
- if (header != NULL && HEADERNODE(header)->locknum != locknum) {
+ if (header != NULL &&
+ qpzone_get_lock(qpdb, HEADERNODE(header)) != nlock)
+ {
RWUNLOCK(&qpdb->lock, isc_rwlocktype_read);
NODE_UNLOCK(nlock, &nlocktype);
- locknum = HEADERNODE(header)->locknum;
+
+ nlock = qpzone_get_lock(qpdb, HEADERNODE(header));
goto again;
}
}
if (rdataset != NULL) {
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
- isc_rwlock_t *nlock =
- &search->qpdb->buckets[node->locknum].lock;
+ isc_rwlock_t *nlock = qpzone_get_lock(search->qpdb, node);
NODE_RDLOCK(nlock, &nlocktype);
bindrdataset(search->qpdb, node, search->zonecut_header,
rdataset DNS__DB_FLARG_PASS);
result = dns_qpiter_current(it, nodename, (void **)&node, NULL);
while (result == ISC_R_SUCCESS) {
- isc_rwlock_t *nlock = &qpdb->buckets[node->locknum].lock;
+ isc_rwlock_t *nlock = qpzone_get_lock(qpdb, node);
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
dns_slabheader_t *header_next = NULL;
dns_qpchain_node(&search->chain, i, NULL, (void **)&node, NULL);
- nlock = &qpdb->buckets[node->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, node);
NODE_RDLOCK(nlock, &nlocktype);
/*
* First we try to figure out if this node is active in
* is active in the search's version, we're
* done.
*/
- nlock = &qpdb->buckets[wnode->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, wnode);
NODE_RDLOCK(nlock, &nlocktype);
for (header = wnode->data; header != NULL;
header = header->next)
do {
dns_slabheader_t *found = NULL, *foundsig = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
- isc_rwlock_t *nlock =
- &search->qpdb->buckets[node->locknum].lock;
+ isc_rwlock_t *nlock = qpzone_get_lock(search->qpdb, node);
NODE_RDLOCK(nlock, &nlocktype);
empty_node = true;
for (header = node->data; header != NULL; header = header_next)
dns_slabheader_t *found = NULL;
isc_result_t result = DNS_R_CONTINUE;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
- isc_rwlock_t *nlock = &search->qpdb->buckets[node->locknum].lock;
+ isc_rwlock_t *nlock = qpzone_get_lock(search->qpdb, node);
NODE_RDLOCK(nlock, &nlocktype);
* have matched a wildcard.
*/
- nlock = &search.qpdb->buckets[node->locknum].lock;
+ nlock = qpzone_get_lock(search.qpdb, node);
NODE_RDLOCK(nlock, &nlocktype);
if (search.zonecut != NULL) {
if (search.need_cleanup) {
node = search.zonecut;
INSIST(node != NULL);
- nlock = &search.qpdb->buckets[node->locknum].lock;
+ nlock = qpzone_get_lock(search.qpdb, node);
NODE_RDLOCK(nlock, &nlocktype);
qpznode_release(search.qpdb, node, 0,
node = (qpznode_t *)(*nodep);
*nodep = NULL;
- nlock = &qpdb->buckets[node->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, node);
/*
* qpzone_destroy() uses call_rcu() API to destroy the node locks, so it
qpzonedb_t *qpdb = (qpzonedb_t *)db;
qpznode_t *node = (qpznode_t *)dbnode;
- RWLOCK(&qpdb->buckets[node->locknum].lock, type);
+ RWLOCK(qpzone_get_lock(qpdb, node), type);
}
static void
qpzonedb_t *qpdb = (qpzonedb_t *)db;
qpznode_t *node = (qpznode_t *)dbnode;
- RWUNLOCK(&qpdb->buckets[node->locknum].lock, type);
+ RWUNLOCK(qpzone_get_lock(qpdb, node), type);
}
static void
qpz_version_t *version = (qpz_version_t *)qrditer->common.version;
dns_slabheader_t *header = NULL, *top_next = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
- isc_rwlock_t *nlock = &qpdb->buckets[node->locknum].lock;
+ isc_rwlock_t *nlock = qpzone_get_lock(qpdb, node);
NODE_RDLOCK(nlock, &nlocktype);
dns_slabheader_t *header = NULL;
dns_slabheader_t *topheader, *topheader_next = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
- isc_rwlock_t *nlock = &qpdb->buckets[node->locknum].lock;
+ isc_rwlock_t *nlock = qpzone_get_lock(qpdb, node);
header = qrditer->current;
if (header == NULL) {
qpznode_t *node = (qpznode_t *)qrditer->common.node;
dns_slabheader_t *header = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
- isc_rwlock_t *nlock = &qpdb->buckets[node->locknum].lock;
+ isc_rwlock_t *nlock = qpzone_get_lock(qpdb, node);
header = qrditer->current;
REQUIRE(header != NULL);
}
iter->node = NULL;
- nlock = &qpdb->buckets[node->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, node);
NODE_RDLOCK(nlock, &nlocktype);
qpznode_release(qpdb, node, 0, &nlocktype DNS__DB_FLARG_PASS);
* (Note: node lock must be acquired after starting
* the QPDB transaction and released before committing.)
*/
- nlock = &qpdb->buckets[node->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, node);
NODE_WRLOCK(nlock, &nlocktype);
newheader->resign_lsb = rdataset->resign & 0x1;
}
- nlock = &qpdb->buckets[node->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, node);
NODE_WRLOCK(nlock, &nlocktype);
changed = add_changed(newheader, version DNS__DB_FLARG_PASS);
dns_name_copy(&node->name, nodename);
- nlock = &qpdb->buckets[node->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, node);
NODE_WRLOCK(nlock, &nlocktype);
result = add(qpdb, node, nodename, version, newheader, DNS_DBADD_FORCE,
false, NULL, 0 DNS__DB_FLARG_PASS);
REQUIRE(node != NULL);
REQUIRE(name != NULL);
- nlock = &qpdb->buckets[qpnode->locknum].lock;
+ nlock = qpzone_get_lock(qpdb, qpnode);
NODE_RDLOCK(nlock, &nlocktype);
dns_name_copy(&qpnode->name, name);