mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-01 15:05:23 +00:00
Support for off-loop read-ony qp-trie transactions
It is sometimes necessary to access a qp-trie outside an isc_loop, such as in tests or an isc_work callback. The best option was to use a `dns_qpmulti_write()` transaction, but that has overheads that are not necessary for read-only access, such as committing a new version of the trie even when nothing changed. So this commit adds a `dns_qpmulti_read()` transaction, which is nearly as lightweight as a query transaction, but it takes the mutex like a write transaction.
This commit is contained in:
@@ -53,6 +53,12 @@
|
|||||||
* lifetime of a `dns_qpread_t`, instead of using locks. Readers are
|
* lifetime of a `dns_qpread_t`, instead of using locks. Readers are
|
||||||
* not blocked by any write activity, and vice versa.
|
* not blocked by any write activity, and vice versa.
|
||||||
*
|
*
|
||||||
|
* For read-only access outside the scope of a loop, such as from an
|
||||||
|
* isc_work callback, `dns_qpmulti_lockedread()`. This looks like a
|
||||||
|
* query transaction; the difference is that a locked read transaction
|
||||||
|
* takes the `dns_qpmulti_t` mutex. When you have finished with a
|
||||||
|
* `dns_qpread_t`, call `dns_qpread_destroy()` to release the mutex.
|
||||||
|
*
|
||||||
* For reads that need a stable view of the trie for multiple cycles
|
* For reads that need a stable view of the trie for multiple cycles
|
||||||
* of an isc_loop, or which can be used from any thread, call
|
* of an isc_loop, or which can be used from any thread, call
|
||||||
* `dns_qpmulti_snapshot()` to get a `dns_qpsnap_t`. A snapshot is for
|
* `dns_qpmulti_snapshot()` to get a `dns_qpsnap_t`. A snapshot is for
|
||||||
@@ -598,10 +604,27 @@ dns_qpmulti_query(dns_qpmulti_t *multi, dns_qpread_t *qpr);
|
|||||||
* \li `qpr` is a valid read-only qp-trie handle
|
* \li `qpr` is a valid read-only qp-trie handle
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_qpmulti_lockedread(dns_qpmulti_t *multi, dns_qpread_t *qpr);
|
||||||
|
/*%<
|
||||||
|
* Start a read-only transaction that takes the `dns_qpmulti_t` mutex.
|
||||||
|
*
|
||||||
|
* The `dns_qpmulti_lockedread()` function must NOT be called from an
|
||||||
|
* isc_loop thread. We keep query and read transactions separate to
|
||||||
|
* avoid accidentally taking or failing to take the mutex.
|
||||||
|
*
|
||||||
|
* Requires:
|
||||||
|
* \li `multi` is a pointer to a valid multi-threaded qp-trie
|
||||||
|
* \li `qpr != NULL`
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* \li `qpr` is a valid read-only qp-trie handle
|
||||||
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
dns_qpread_destroy(dns_qpmulti_t *multi, dns_qpread_t *qpr);
|
dns_qpread_destroy(dns_qpmulti_t *multi, dns_qpread_t *qpr);
|
||||||
/*%<
|
/*%<
|
||||||
* End a lightweight read transaction.
|
* End a lightweight query or read transaction.
|
||||||
*
|
*
|
||||||
* Requires:
|
* Requires:
|
||||||
* \li `multi` is a pointer to a valid multi-threaded qp-trie
|
* \li `multi` is a pointer to a valid multi-threaded qp-trie
|
||||||
|
30
lib/dns/qp.c
30
lib/dns/qp.c
@@ -1282,12 +1282,31 @@ dns_qpmulti_query(dns_qpmulti_t *multi, dns_qpread_t *qp) {
|
|||||||
REQUIRE(QPMULTI_VALID(multi));
|
REQUIRE(QPMULTI_VALID(multi));
|
||||||
REQUIRE(qp != NULL);
|
REQUIRE(qp != NULL);
|
||||||
|
|
||||||
dns_qpmulti_t *whence = reader_open(multi, qp);
|
/* we MUST be in an isc_loop thread */
|
||||||
INSIST(whence == multi);
|
|
||||||
|
|
||||||
/* we must be in an isc_loop thread */
|
|
||||||
qp->tid = isc_tid();
|
qp->tid = isc_tid();
|
||||||
REQUIRE(qp->tid != ISC_TID_UNKNOWN);
|
REQUIRE(qp->tid != ISC_TID_UNKNOWN);
|
||||||
|
|
||||||
|
dns_qpmulti_t *whence = reader_open(multi, qp);
|
||||||
|
INSIST(whence == multi);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* a locked read takes the mutex
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
dns_qpmulti_lockedread(dns_qpmulti_t *multi, dns_qpread_t *qp) {
|
||||||
|
REQUIRE(QPMULTI_VALID(multi));
|
||||||
|
REQUIRE(qp != NULL);
|
||||||
|
|
||||||
|
/* we MUST NOT be in an isc_loop thread */
|
||||||
|
qp->tid = isc_tid();
|
||||||
|
REQUIRE(qp->tid == ISC_TID_UNKNOWN);
|
||||||
|
|
||||||
|
LOCK(&multi->mutex);
|
||||||
|
|
||||||
|
dns_qpmulti_t *whence = reader_open(multi, qp);
|
||||||
|
INSIST(whence == multi);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -1295,6 +1314,9 @@ dns_qpread_destroy(dns_qpmulti_t *multi, dns_qpread_t *qp) {
|
|||||||
REQUIRE(QPMULTI_VALID(multi));
|
REQUIRE(QPMULTI_VALID(multi));
|
||||||
REQUIRE(QP_VALID(qp));
|
REQUIRE(QP_VALID(qp));
|
||||||
REQUIRE(qp->tid == isc_tid());
|
REQUIRE(qp->tid == isc_tid());
|
||||||
|
if (qp->tid == ISC_TID_UNKNOWN) {
|
||||||
|
UNLOCK(&multi->mutex);
|
||||||
|
}
|
||||||
*qp = (dns_qpread_t){};
|
*qp = (dns_qpread_t){};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user