* PERFORMANCE OF THIS SOFTWARE.
*/
-/* $Id: acache.c,v 1.16 2006/05/03 00:07:50 marka Exp $ */
+/* $Id: acache.c,v 1.17 2006/06/28 08:28:49 jinmei Exp $ */
#include <config.h>
#define DNS_ACACHE_MINSIZE 2097152 /* Bytes. 2097152 = 2 MB */
#define DNS_ACACHE_CLEANERINCREMENT 1000 /* Number of entries. */
+#define DEFAULT_ACACHE_ENTRY_LOCK_COUNT 1009 /*%< Should be prime. */
+
#if defined(ISC_RWLOCK_USEATOMIC) && defined(ISC_PLATFORM_HAVEATOMICSTORE)
#define ACACHE_USE_RWLOCK 1
#endif
isc_mem_t *mctx;
isc_refcount_t refs;
+#ifdef ACACHE_USE_RWLOCK
+ isc_rwlock_t *entrylocks;
+#else
+ isc_mutex_t *entrylocks;
+#endif
+
isc_mutex_t lock;
int live_cleaners;
struct dns_acacheentry {
unsigned int magic;
-#ifdef ACACHE_USE_RWLOCK
- isc_rwlock_t lock;
-#else
- isc_mutex_t lock;
-#endif
+ unsigned int locknum;
isc_refcount_t references;
dns_acache_t *acache;
entry = entry_next) {
entry_next = ISC_LIST_NEXT(entry, link);
- ACACHE_LOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_LOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
/*
* If the cleaner holds this entry, it will be unlinked and
entry->callback = NULL;
}
- ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
if (acache->cleaner.current_entry != entry)
dns_acache_detachentry(&entry);
*/
clear_entry(acache, entry);
- ACACHE_DESTROYLOCK(&entry->lock);
-
isc_mem_put(acache->mctx, entry, sizeof(*entry));
dns_acache_detach(&acache);
static void
destroy(dns_acache_t *acache) {
+ int i;
+
REQUIRE(DNS_ACACHE_VALID(acache));
ATRACE("destroy");
if (acache->task != NULL)
isc_task_detach(&acache->task);
+ for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++)
+ ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
+ isc_mem_put(acache->mctx, acache->entrylocks,
+ sizeof(*acache->entrylocks) *
+ DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
+
DESTROYLOCK(&acache->cleaner.lock);
DESTROYLOCK(&acache->lock);
while (n_entries-- > 0) {
isc_boolean_t is_stale = ISC_FALSE;
-
+
INSIST(entry != NULL);
next = ISC_LIST_NEXT(entry, link);
- ACACHE_LOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_LOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
is_stale = entry_stale(cleaner, entry, now32, interval);
if (is_stale) {
cleaner->ncleaned++;
}
- ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
if (is_stale)
dns_acache_detachentry(&entry);
acache->shutting_down = ISC_FALSE;
acache->task = NULL;
+ acache->entrylocks = NULL;
+
result = isc_task_create(taskmgr, 1, &acache->task);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
for (i = 0; i < DBBUCKETS; i++)
ISC_LIST_INIT(acache->dbbucket[i]);
+ acache->entrylocks = isc_mem_get(mctx, sizeof(*acache->entrylocks) *
+ DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
+ if (acache->entrylocks == NULL) {
+ result = ISC_R_NOMEMORY;
+ goto cleanup;
+ }
+ for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++) {
+ result = ACACHE_INITLOCK(&acache->entrylocks[i]);
+ if (result != ISC_R_SUCCESS) {
+ while (i-- > 0)
+ ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
+ isc_mem_put(mctx, acache->entrylocks,
+ sizeof(*acache->entrylocks) *
+ DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
+ acache->entrylocks = NULL;
+ goto cleanup;
+ }
+ }
+
acache->live_cleaners = 0;
result = acache_cleaner_init(acache, timermgr, &acache->cleaner);
if (result != ISC_R_SUCCESS)
DESTROYLOCK(&acache->lock);
isc_refcount_decrement(&acache->refs, NULL);
isc_refcount_destroy(&acache->refs);
+ if (acache->entrylocks != NULL) {
+ for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++)
+ ACACHE_DESTROYLOCK(&acache->entrylocks[i]);
+ isc_mem_put(mctx, acache->entrylocks,
+ sizeof(*acache->entrylocks) *
+ DEFAULT_ACACHE_ENTRY_LOCK_COUNT);
+ }
isc_mem_put(mctx, acache, sizeof(*acache));
isc_mem_detach(&mctx);
* original holder has canceled callback,) destroy it here.
*/
while ((entry = ISC_LIST_HEAD(dbentry->originlist)) != NULL) {
- ACACHE_LOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_LOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
/*
* Releasing olink first would avoid finddbent() in
(entry->callback)(entry, &entry->cbarg);
entry->callback = NULL;
- ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
if (acache->cleaner.current_entry != entry)
dns_acache_detachentry(&entry);
}
while ((entry = ISC_LIST_HEAD(dbentry->referlist)) != NULL) {
- ACACHE_LOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_LOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
ISC_LIST_UNLINK(dbentry->referlist, entry, rlink);
if (acache->cleaner.current_entry != entry)
(entry->callback)(entry, &entry->cbarg);
entry->callback = NULL;
- ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
if (acache->cleaner.current_entry != entry)
dns_acache_detachentry(&entry);
{
dns_acacheentry_t *newentry;
isc_result_t result;
+ isc_uint32_t r;
REQUIRE(DNS_ACACHE_VALID(acache));
REQUIRE(entryp != NULL && *entryp == NULL);
return (ISC_R_NOMEMORY);
}
- result = ACACHE_INITLOCK(&newentry->lock);
- if (result != ISC_R_SUCCESS) {
- isc_mem_put(acache->mctx, newentry, sizeof(*newentry));
- return (result);
- };
-
+ isc_random_get(&r);
+ newentry->locknum = r % DEFAULT_ACACHE_ENTRY_LOCK_COUNT;
+
result = isc_refcount_init(&newentry->references, 1);
if (result != ISC_R_SUCCESS) {
- ACACHE_DESTROYLOCK(&newentry->lock);
isc_mem_put(acache->mctx, newentry, sizeof(*newentry));
return (result);
};
isc_result_t result = ISC_R_SUCCESS;
dns_rdataset_t *erdataset;
isc_stdtime32_t now32;
+ dns_acache_t *acache;
+ int locknum;
REQUIRE(DNS_ACACHEENTRY_VALID(entry));
REQUIRE(zonep == NULL || *zonep == NULL);
REQUIRE(nodep != NULL && *nodep == NULL);
REQUIRE(fname != NULL);
REQUIRE(msg != NULL);
-
- ACACHE_LOCK(&entry->lock, isc_rwlocktype_read);
+ acache = entry->acache;
+ REQUIRE(DNS_ACACHE_VALID(acache));
+
+ locknum = entry->locknum;
+ ACACHE_LOCK(&acache->entrylocks[locknum], isc_rwlocktype_read);
isc_stdtime_convert32(now, &now32);
acache_storetime(entry, now32);
ardataset = NULL;
result = dns_message_gettemprdataset(msg, &ardataset);
if (result != ISC_R_SUCCESS) {
- ACACHE_UNLOCK(&entry->lock,
+ ACACHE_UNLOCK(&acache->entrylocks[locknum],
isc_rwlocktype_read);
goto fail;
}
entry->acache->stats.hits++; /* XXXMLG danger: unlocked! */
entry->acache->stats.queries++;
- ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_read);
+ ACACHE_UNLOCK(&acache->entrylocks[locknum], isc_rwlocktype_read);
return (result);
REQUIRE(DNS_ACACHEENTRY_VALID(entry));
LOCK(&acache->lock); /* XXX: need to lock it here for ordering */
- ACACHE_LOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write);
/* Set zone */
if (zone != NULL)
*/
dns_acache_attachentry(entry, &dummy_entry);
- ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
acache->stats.adds++;
UNLOCK(&acache->lock);
fail:
clear_entry(acache, entry);
- ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
UNLOCK(&acache->lock);
return (result);
INSIST(DNS_ACACHE_VALID(acache));
LOCK(&acache->lock);
- ACACHE_LOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write);
/*
* Release dependencies stored in this entry as much as possible.
entry->callback = NULL;
entry->cbarg = NULL;
- ACACHE_UNLOCK(&entry->lock, isc_rwlocktype_write);
+ ACACHE_UNLOCK(&acache->entrylocks[entry->locknum],
+ isc_rwlocktype_write);
UNLOCK(&acache->lock);
}